home *** CD-ROM | disk | FTP | other *** search
/ Enter 2007 April / ENTER_CD_04_07.iso / Internet / WinHTTrack 3.23 / httrack-3.23.exe / {app} / src / htsback.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-03-08  |  104.6 KB  |  2,740 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       backing system (multiple socket download)              */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsback.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htsnet.h"
  43. #include "htsthread.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <time.h>
  48. /* END specific definitions */
  49.  
  50. //#if HTS_WIN
  51. #include "htsftp.h"
  52. #if HTS_USEZLIB
  53. #include "htszlib.h"
  54. #endif
  55. //#endif
  56.  
  57. #if HTS_WIN
  58. #ifndef __cplusplus
  59. // DOS
  60. #include <process.h>    /* _beginthread, _endthread */
  61. #endif
  62. #else
  63. #endif
  64.  
  65. #undef test_flush
  66. #define test_flush if (opt->flush) { if (opt->log) { fflush(opt->log); } if (opt->errlog) { fflush(opt->errlog);  } }
  67.  
  68. #define VT_CLREOL       "\33[K"
  69.  
  70.  
  71. // ---
  72. // routines de backing
  73. // retourne l'index d'un lien dans un tableau de backing
  74. int back_index(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  75.   int i=0;
  76.   int index=-1;
  77.   while( i<back_max ) {
  78.     if (back[i].status>=0)    // rΘception OU prΩt
  79.       if (strfield2(back[i].url_adr,adr)) {
  80.         if (strcmp(back[i].url_fil,fil)==0) {
  81.           if (index==-1)    /* first time we meet, store it */
  82.             index=i;
  83.           else if (strcmp(back[i].url_sav,sav)==0) {  /* oops, check sav too */
  84.             index=i;
  85.             return index;
  86.           }
  87.         }
  88.       }
  89.     i++;
  90.   }
  91.   return index;
  92. }
  93.  
  94. // nombre d'entrΘes libres dans le backing
  95. int back_available(lien_back* back,int back_max) {
  96.   int i;
  97.   int nb=0;
  98.   for(i=0;i<back_max;i++)
  99.     if (back[i].status==-1)     /* libre */
  100.       nb++;
  101.   return nb;
  102. }
  103.  
  104. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  105. LLint back_incache(lien_back* back,int back_max) {
  106.   int i;
  107.   LLint sum=0;
  108.   for(i=0;i<back_max;i++)
  109.     if (back[i].status!=-1)
  110.       if (back[i].r.adr)       // ne comptabilier que les blocs en mΘmoire
  111.         sum+=max(back[i].r.size,back[i].r.totalsize);
  112.   return sum;
  113. }
  114.  
  115. // le lien a-t-il ΘtΘ mis en backing?
  116. HTS_INLINE int back_exist(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  117.   return (back_index(back,back_max,adr,fil,sav)>=0);
  118. }
  119.  
  120. // nombre de sockets en tΓche de fond
  121. int back_nsoc(lien_back* back,int back_max) {
  122.   int n=0;
  123.   int i;
  124.   for(i=0;i<back_max;i++)
  125.     if (back[i].status > 0)    // only receive
  126.       n++;
  127.  
  128.   return n;
  129. }
  130. int back_nsoc_overall(lien_back* back,int back_max) {
  131.   int n=0;
  132.   int i;
  133.   for(i=0;i<back_max;i++)
  134.     if (back[i].status > 0 || back[i].status == -103)
  135.       n++;
  136.  
  137.   return n;
  138. }
  139.  
  140. // objet (lien) tΘlΘchargΘ ou transfΘrΘ depuis le cache
  141. //
  142. // fermer les paramΦtres de transfert,
  143. // et notamment vΘrifier les fichiers compressΘs (dΘcompresser), callback etc.
  144. int back_finalize(httrackp* opt,cache_back* cache,lien_back* back,int p) {
  145.   if (
  146.       (back[p].status == 0)      // ready
  147.       &&
  148.       (!back[p].testmode)        // not test mode
  149.       &&
  150.       (back[p].r.statuscode>0)   // not internal error
  151.       ) {
  152.     char* state="unknown";
  153.    
  154.     /* dΘcompression */
  155. #if HTS_USEZLIB
  156.     if (gz_is_available && back[p].r.compressed) {
  157.       if (back[p].r.size > 0) {
  158.         //if ( (back[p].r.adr) && (back[p].r.size>0) ) {
  159.         // stats
  160.         back[p].compressed_size=back[p].r.size;
  161.         // en mΘmoire -> passage sur disque
  162.         if (!back[p].r.is_write) {
  163.           back[p].tmpfile[0]='\0';
  164.           strcpybuff(back[p].tmpfile,tempnam(NULL,"httrz"));
  165.           if (back[p].tmpfile[0]) {
  166.             back[p].r.out=fopen(back[p].tmpfile,"wb");
  167.             if (back[p].r.out) {
  168.               if ((back[p].r.adr) && (back[p].r.size>0)) {
  169.                 if (fwrite(back[p].r.adr,1,(INTsys)back[p].r.size,back[p].r.out) != back[p].r.size) {
  170.                   back[p].r.statuscode=-1;
  171.                   strcpybuff(back[p].r.msg,"Write error when decompressing");
  172.                 }
  173.               } else {
  174.                 back[p].tmpfile[0]='\0';
  175.                 back[p].r.statuscode=-1;
  176.                 strcpybuff(back[p].r.msg,"Empty compressed file");
  177.               }
  178.             } else {
  179.               back[p].tmpfile[0]='\0';
  180.               back[p].r.statuscode=-1;
  181.               strcpybuff(back[p].r.msg,"Open error when decompressing");
  182.             }
  183.           }
  184.         }
  185.         // fermer fichier sortie
  186.         if (back[p].r.out!=NULL) {
  187.           fclose(back[p].r.out);
  188.           back[p].r.out=NULL;
  189.         }
  190.         // dΘcompression
  191.         if (back[p].tmpfile[0] && back[p].url_sav[0]) {
  192.           LLint size;
  193.           filecreateempty(back[p].url_sav);      // filenote & co
  194.           if ((size = hts_zunpack(back[p].tmpfile,back[p].url_sav))>=0) {
  195.             back[p].r.size=back[p].r.totalsize=size;
  196.             // fichier -> mΘmoire
  197.             if (!back[p].r.is_write) {
  198.               back[p].r.adr=readfile(back[p].url_sav);
  199.               if (!back[p].r.adr) {
  200.                 back[p].r.statuscode=-1;
  201.                 strcpybuff(back[p].r.msg,"Read error when decompressing");
  202.               }
  203.               remove(back[p].url_sav);
  204.             }
  205.           }
  206.           remove(back[p].tmpfile);
  207.         }
  208.         // stats
  209.         HTS_STAT.total_packed+=back[p].compressed_size;
  210.         HTS_STAT.total_unpacked+=back[p].r.size;
  211.         HTS_STAT.total_packedfiles++;
  212.         // unflag
  213.       }
  214.     }
  215.     back[p].r.compressed=0;
  216. #endif
  217.     
  218.     /* Stats */
  219.     if (cache->txt) {
  220.       char flags[32];
  221.       char s[256];
  222.       time_t tt;
  223.       struct tm* A;
  224.       tt=time(NULL);
  225.       A=localtime(&tt);
  226.       strftime(s,250,"%H:%M:%S",A);
  227.       
  228.       flags[0]='\0';
  229.       /* input flags */
  230.       if (back[p].is_update)
  231.         strcatbuff(flags, "U");   // update request
  232.       else
  233.         strcatbuff(flags, "-");
  234.       if (back[p].range_req_size)
  235.         strcatbuff(flags, "R");   // range request
  236.       else
  237.         strcatbuff(flags, "-");
  238.       /* state flags */
  239.       if (back[p].r.is_file)  // direct to disk
  240.         strcatbuff(flags, "F");
  241.       else
  242.         strcatbuff(flags, "-");
  243.       /* output flags */
  244.       if (!back[p].r.notmodified)
  245.         strcatbuff(flags, "M");   // modified
  246.       else
  247.         strcatbuff(flags, "-");
  248.       if (back[p].r.is_chunk)  // chunked
  249.         strcatbuff(flags, "C");
  250.       else
  251.         strcatbuff(flags, "-");
  252.       if (back[p].r.compressed)
  253.         strcatbuff(flags, "Z");   // gzip
  254.       else
  255.         strcatbuff(flags, "-");
  256.       /* Err I had to split these.. */
  257.       fprintf(cache->txt,"%s\t", s);
  258.       fprintf(cache->txt,LLintP"/", (LLint)back[p].r.size);
  259.       fprintf(cache->txt,LLintP,(LLint)back[p].r.totalsize);
  260.       fprintf(cache->txt,"\t%s\t",flags);
  261.     }
  262.     if (back[p].r.statuscode==200) {
  263.       if (back[p].r.size>=0) {
  264.         if (strcmp(back[p].url_fil,"/robots.txt") !=0 ) {
  265.           HTS_STAT.stat_bytes+=back[p].r.size;
  266.           HTS_STAT.stat_files++;
  267.         }
  268.         if ( (!back[p].r.notmodified) && (opt->is_update) ) { 
  269.           HTS_STAT.stat_updated_files++;       // page modifiΘe
  270.           if (opt->log!=NULL) {
  271.             fspc(opt->log,"info");
  272.             if (back[p].is_update) {
  273.               fprintf(opt->log,"engine: transfer-status: link updated: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  274.             } else {
  275.               fprintf(opt->log,"engine: transfer-status: link added: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  276.             }
  277.             test_flush;
  278.           }
  279.           if (cache->txt) {
  280.             if (back[p].is_update) {
  281.               state="updated";
  282.             } else {
  283.               state="added";
  284.             }
  285.           }
  286.         } else {
  287.           if ( (opt->debug>0) && (opt->log!=NULL) ) {
  288.             fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link recorded: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  289.             test_flush;
  290.           }
  291.           if (cache->txt) {
  292.             if (opt->is_update)
  293.               state="untouched";
  294.             else
  295.               state="added";
  296.           }
  297.         }
  298.       } else {
  299.         if ( (opt->debug>0) && (opt->log!=NULL) ) {
  300.           fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: empty file? (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  301.           test_flush;
  302.         }
  303.         if (cache->txt) {
  304.           state="empty";
  305.         }
  306.       }
  307.     } else {
  308.       if ( (opt->debug>0) && (opt->log!=NULL) ) {
  309.         fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link error (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  310.       }
  311.       if (cache->txt) {
  312.         state="error";
  313.       }
  314.     }
  315.     if (cache->txt) {
  316.       fprintf(cache->txt,
  317.         "%d\t"
  318.         "%s ('%s')\t"
  319.         "%s\t"
  320.         "%s%s\t"
  321.         "%s%s\t%s\t"
  322.         "(from %s%s)"
  323.         LF,
  324.         back[p].r.statuscode,
  325.         state, escape_check_url_addr(back[p].r.msg),
  326.         escape_check_url_addr(back[p].r.contenttype),
  327.         ((back[p].r.etag[0])?"etag:":((back[p].r.lastmodified[0])?"date:":"")), escape_check_url_addr((back[p].r.etag[0])?back[p].r.etag:(back[p].r.lastmodified)),
  328.         escape_check_url_addr(back[p].url_adr),escape_check_url_addr(back[p].url_fil),escape_check_url_addr(back[p].url_sav),
  329.         escape_check_url_addr(back[p].referer_adr),escape_check_url_addr(back[p].referer_fil)
  330.         );
  331.       if (opt->flush)
  332.         fflush(cache->txt);
  333.     }
  334.     
  335.     /* Cache */
  336.     cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  337.     
  338.     // status finished callback
  339. #if HTS_ANALYSTE
  340.     hts_htmlcheck_xfrstatus(&back[p]);
  341. #endif
  342.     return 0;
  343.   }
  344.   return -1;
  345. }
  346.  
  347. /* try to keep the connection alive */
  348. int back_letlive(htsblk* src) {
  349.   if (src && !src->is_file 
  350.     && src->soc != INVALID_SOCKET
  351.     && src->statuscode >= 0           /* no timeout errors & co */
  352.     && src->keep_alive_trailers == 0  /* not yet supported (chunk trailers) */
  353.     && !check_sockerror(src->soc)
  354.     /*&& !check_sockdata(src->soc)*/     /* no unexpected data */
  355.     ) {
  356.     htsblk tmp;
  357.     memset(&tmp, 0, sizeof(tmp));
  358.     /* clear everything but connection: switch, close, and reswitch */
  359.     back_connxfr(src, &tmp);
  360.     deletehttp(src);
  361.     back_connxfr(&tmp, src);
  362.     src->req.flush_garbage=1;     /* ignore CRLF garbage */
  363.     return 1;
  364.   }
  365.   return 0;
  366. }
  367.  
  368. void back_connxfr(htsblk* src, htsblk* dst) {
  369.   dst->soc = src->soc;
  370.   src->soc = INVALID_SOCKET;
  371. #if HTS_USEOPENSSL
  372.   dst->ssl = src->ssl;
  373.   src->ssl = 0;
  374.   dst->ssl_con = src->ssl_con;
  375.   src->ssl_con = NULL;
  376. #endif
  377.   dst->keep_alive = src->keep_alive;
  378.   src->keep_alive = 0;
  379.   dst->keep_alive_max = src->keep_alive_max;
  380.   src->keep_alive_max = 0;
  381.   dst->keep_alive_t = src->keep_alive_t;
  382.   src->keep_alive_t = 0;
  383.   dst->debugid = src->debugid;
  384.   src->debugid = 0;
  385. }
  386.  
  387. // clear, or leave for keep-alive
  388. int back_maydelete(lien_back* back, httrackp* opt, int p) {
  389.   if (p>=0) {    // on sait jamais..
  390.     if (!opt->nokeepalive
  391.       && back[p].r.keep_alive 
  392.       && back[p].r.keep_alive_max > 1
  393.       && back[p].ka_time_start 
  394.       && time_local() < back[p].ka_time_start + back[p].r.keep_alive_t
  395.       ) {
  396.       lien_back tmp;
  397.       strcpybuff(tmp.url_adr, back[p].url_adr);
  398.       if (back_letlive(&back[p].r)) {
  399.         strcpybuff(back[p].url_adr, tmp.url_adr);
  400.         back[p].status = -103;  // alive & waiting
  401.         if ((opt->debug>1) && (opt->log!=NULL)) {
  402.           fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): successfully saved #%d (%s)"LF, 
  403.             back[p].r.debugid,
  404.             back[p].url_adr); test_flush;
  405.         }
  406.         return 1;
  407.       }
  408.     }
  409.     back_delete(back, p);
  410.   }
  411.   return 0;
  412. }
  413.  
  414. // clear, or leave for keep-alive
  415. void back_maydeletehttp(lien_back* back, int back_max, httrackp* opt, int p) {
  416.   int q;
  417.   if (!opt->nokeepalive
  418.     && back[p].r.keep_alive 
  419.     && back[p].r.keep_alive_max > 1
  420.     && back[p].ka_time_start 
  421.     && time_local() < back[p].ka_time_start + back[p].r.keep_alive_t
  422.     && ( q = back_search(back, back_max) ) >= 0
  423.     ) {
  424.     lien_back tmp;
  425.     strcpybuff(tmp.url_adr, back[p].url_adr);
  426.     deletehttp(&back[q].r);               // security check
  427.     back_connxfr(&back[p].r, &back[q].r); // transfer live connection settings from p to q
  428.     back[q].ka_time_start = back[p].ka_time_start;  // refresh
  429.     back[p].r.soc = INVALID_SOCKET;
  430.     strcpybuff(back[q].url_adr, tmp.url_adr); // address
  431.     back[q].status = -103;  // alive & waiting
  432.     if ((opt->debug>1) && (opt->log!=NULL)) {
  433.       fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): successfully preserved #%d (%s)"LF, 
  434.         back[q].r.debugid,
  435.         back[q].url_adr); test_flush;
  436.     }
  437.   } else {
  438.     if (back[p].r.soc!=INVALID_SOCKET) {
  439.       deletehttp(&back[p].r);
  440.       back[p].r.soc = INVALID_SOCKET;
  441.     }
  442.   }
  443. }
  444.  
  445.  
  446. /* attempt to attach a live connection to this slot */
  447. int back_trylive(lien_back* back, int back_max, int p) {
  448.   if (p>=0 && back[p].status != -103) {     // we never know..
  449.     int i = back_searchlive(back, back_max, back[p].url_adr);   // search slot
  450.     if (i >= 0 && i != p) {
  451.       deletehttp(&back[p].r);               // security check
  452.       back_connxfr(&back[i].r, &back[p].r); // transfer live connection settings from i to p
  453.       back_delete(back, i);                 // delete old slot
  454.       back[p].status=100;                   // ready to connect
  455.       return 1;                             // success: will reuse live connection
  456.     }
  457.   }
  458.   return 0;
  459. }
  460.  
  461. /* search for a live position, or, if not possible, try to return a new one */
  462. int back_searchlive(lien_back* back, int back_max, char* search_addr) {
  463.   int i;
  464.  
  465.   /* search for a live socket */
  466.   for(i = 0 ; i < back_max ; i++ ) {
  467.     if (back[i].status == -103) {
  468.       if (strfield2(back[i].url_adr, search_addr)) {   /* same location (xxc: check also virtual hosts?) */
  469.         if (time_local() < back[i].ka_time_start + back[i].r.keep_alive_t) {
  470.           return i;
  471.         }
  472.       }
  473.     }
  474.   }
  475.   return -1;
  476. }
  477.   
  478. int back_search(lien_back* back, int back_max) {
  479.   int i;
  480.  
  481.   /* try to find an empty place */
  482.   for(i = 0 ; i < back_max ; i++ ) {
  483.     if (back[i].status == -1) {
  484.       return i;
  485.     }
  486.   }
  487.  
  488.   /* couldn't find an empty place, try to requisition a keep-alive place */
  489.   for(i = 0 ; i < back_max ; i++ ) {
  490.     if (back[i].status == -103) {
  491.       /* close this place */
  492.       back_delete(back, i);
  493.       return i;
  494.     }
  495.   }
  496.  
  497.   /* oops, can't find a place */
  498.   return -1;
  499. }
  500.  
  501. // effacer entrΘe
  502. int back_delete(lien_back* back,int p) {
  503.   if (p>=0) {    // on sait jamais..
  504.     // VΘrificateur d'intΘgritΘ
  505.     #if DEBUG_CHECKINT
  506.     _CHECKINT(&back[p],"Appel back_delete")
  507.     #endif
  508. #if HTS_DEBUG_CLOSESOCK
  509.     char info[256];
  510.     sprintf(info,"back_delete: #%d\n",p);
  511.     DEBUG_W2(info);
  512. #endif
  513.  
  514.     // LibΘrer tous les sockets, handles, buffers..
  515.     if (back[p].r.soc!=INVALID_SOCKET) {
  516. #if HTS_DEBUG_CLOSESOCK
  517.       DEBUG_W("back_delete: deletehttp\n");
  518. #endif
  519.       deletehttp(&back[p].r);
  520.       back[p].r.soc=INVALID_SOCKET;
  521.     }
  522.     
  523.     if (back[p].r.adr!=NULL) {  // reste un bloc α dΘsallouer
  524.       freet(back[p].r.adr);
  525.       back[p].r.adr=NULL;
  526.     }
  527.     if (back[p].chunk_adr!=NULL) {  // reste un bloc α dΘsallouer
  528.       freet(back[p].chunk_adr);
  529.       back[p].chunk_adr=NULL;
  530.       back[p].chunk_size=0;
  531.       back[p].is_chunk=0;
  532.     }
  533.     // if (back[p].r.is_file) {  // fermer fichier entrΘe
  534.     if (back[p].r.fp!=NULL) {
  535.       fclose(back[p].r.fp);
  536.       back[p].r.fp=NULL;
  537.     }
  538.     // }
  539.  
  540.     /* fichier de sortie */
  541.     if (back[p].r.out!=NULL) {  // fermer fichier sortie
  542.       fclose(back[p].r.out);
  543.       back[p].r.out=NULL;
  544.     }
  545.  
  546.     if (back[p].r.is_write) {     // ecriture directe
  547.       /* Θcrire date "remote" */
  548.       if (strnotempty(back[p].url_sav))          // normalement existe si on a un fichier de sortie
  549.       if (strnotempty(back[p].r.lastmodified))   // last-modified existe
  550.       if (fexist(back[p].url_sav))          // ainsi que le fichier
  551.         set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
  552.  
  553.       /* executer commande utilisateur aprΦs chargement du fichier */
  554.       usercommand(0,NULL,back[p].url_sav);
  555.       back[p].r.is_write=0;
  556.     }
  557.     
  558.     // Tout nettoyer
  559.     memset(&back[p], 0, sizeof(lien_back));  
  560.     back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  561.     
  562.     // Le plus important: libΘrer le champ
  563.     back[p].status=-1;
  564.   }
  565.   return 0;
  566. }
  567.  
  568. /* Space left on backing stack */
  569. int back_stack_available(lien_back* back,int back_max) {
  570.   int p=0,n=0;
  571.   for( ; p < back_max ; p++ )
  572.     if ( back[p].status == -1 )
  573.       n++;
  574.   return n;
  575. }
  576.  
  577. // ajouter un lien en backing
  578. int back_add(lien_back* back,int back_max,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test,int* pass2_ptr) {
  579.   int p=0;
  580.  
  581.   // vΘrifier cohΘrence de adr et fil (non vide!)
  582.   if (strnotempty(adr)==0) {
  583.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  584.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: adr is empty for back_add"LF);
  585.     }
  586.     return -1;    // erreur!
  587.   }
  588.   if (strnotempty(fil)==0) {
  589.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  590.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: fil is empty for back_add"LF);
  591.     }
  592.     return -1;    // erreur!
  593.   }
  594.   // FIN vΘrifier cohΘrence de adr et fil (non vide!)
  595.  
  596.   // rechercher emplacement
  597.   back_clean(opt, cache, back, back_max);
  598.   if ( ( p = back_search(back, back_max) ) >= 0) {
  599.     back[p].send_too[0]='\0';  // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
  600.  
  601.     // clear r
  602.     if (back[p].r.soc!=INVALID_SOCKET) {  /* we never know */
  603.       deletehttp(&back[p].r);
  604.     }
  605.     memset(&(back[p].r), 0, sizeof(htsblk)); 
  606.     back[p].r.soc=INVALID_SOCKET; 
  607.     back[p].r.location=back[p].location_buffer;
  608.  
  609.     // crΘer entrΘe
  610.     strcpybuff(back[p].url_adr,adr);
  611.     strcpybuff(back[p].url_fil,fil);
  612.     strcpybuff(back[p].url_sav,save);
  613.     back[p].pass2_ptr=pass2_ptr;
  614.     // copier referer si besoin
  615.     strcpybuff(back[p].referer_adr,"");
  616.     strcpybuff(back[p].referer_fil,"");
  617.     if ((referer_adr) && (referer_fil)) {       // existe
  618.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  619.         if (referer_adr[0]!='!') {    // non dΘtruit
  620.           if (strcmp(referer_adr,"file://")) {      // PAS file://
  621.             if (strcmp(referer_adr,"primary")) {      // pas referer 1er lien
  622.               strcpybuff(back[p].referer_adr,referer_adr);
  623.               strcpybuff(back[p].referer_fil,referer_fil);
  624.             }
  625.           }
  626.         }
  627.       }
  628.     }
  629.     // sav ne sert α rien pour le moment
  630.     back[p].r.size=0;                   // rien n'a encore ΘtΘ chargΘ
  631.     back[p].r.adr=NULL;                 // pas de bloc de mΘmoire
  632.     back[p].r.is_write=0;               // α priori stockage en mΘmoire
  633.     back[p].maxfile_html=opt->maxfile_html;
  634.     back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
  635.     back[p].testmode=test;              // mode test?
  636.     if (!opt->http10)                 // option "forcer 1.0" dΘsactivΘe
  637.       back[p].http11=1;               // autoriser http/1.1
  638.     back[p].head_request=0;
  639.     if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0)    // HEAD
  640.       back[p].head_request=1;
  641.     else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0)    // test en GET
  642.       back[p].head_request=2;       // test en get
  643.  
  644.     /* Stop requested - abort backing */
  645.     if (opt->state.stop) {
  646.       back[p].r.statuscode=-1;        // fatal
  647.       strcpybuff(back[p].r.msg,"mirror stopped by user");
  648.       back[p].status=0;  // terminΘ
  649.       if ((opt->debug>0) && (opt->log!=NULL)) {
  650.         fspc(opt->log,"warning"); fprintf(opt->log,"File not added due to mirror cancel: %s%s"LF,adr,fil); test_flush;
  651.       }            
  652.       return 0;
  653.     }
  654.  
  655.     // tester cache
  656.     if ((strcmp(adr,"file://"))           /* pas fichier */
  657.       && ( (!test) || (cache->type==1) )   /* cache prioritaire, laisser passer en test! */
  658.       && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) {  // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
  659.       //if ((!test) && (strcmp(adr,"file://")) 
  660.       //if ((!test) && (strncmp(adr,"ftp://",6)) && (strcmp(adr,"file://")) 
  661. #if HTS_FAST_CACHE
  662.       long int hash_pos;
  663.       int hash_pos_return=0;
  664. #else
  665.       char* a=NULL;
  666. #endif
  667. #if HTS_FAST_CACHE
  668.       if (cache->hashtable) { 
  669. #else
  670.       if (cache->use) { 
  671. #endif
  672.         char buff[HTS_URLMAXSIZE*4];
  673. #if HTS_FAST_CACHE
  674.         strcpybuff(buff,adr); strcatbuff(buff,fil);
  675.         hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  676. #else
  677.         buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  678.         a=strstr(cache->use,buff);
  679. #endif
  680.         
  681.         // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
  682. #if HTS_FAST_CACHE
  683.         if (hash_pos_return) {
  684. #else
  685.         if (a) {
  686. #endif
  687.           if (!test) {      // non mode test
  688. #if HTS_FAST_CACHE
  689.             int pos=hash_pos;
  690. #else
  691.             int pos=-1;
  692.             a+=strlen(buff);
  693.             sscanf(a,"%d",&pos);    // lire position
  694. #endif
  695.             if (pos<0) {    // pas de mise en cache data, vΘrifier existence
  696.               if (fsize(antislash(save)) <= 0) {  // fichier existe pas ou est vide!
  697. #if HTS_FAST_CACHE
  698.                 hash_pos_return=0;
  699. #else
  700.                 a=NULL;    
  701. #endif
  702.                 // dΘvalider car non prΘsent sur disque dans structure originale!!!
  703.                 // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
  704.                 // en Ωtre s√r
  705.                 if (opt->norecatch) {              // tester norecatch
  706.                   if (!fexist(antislash(save))) {  // fichier existe pas mais dΘclarΘ: on l'a effacΘ
  707.                     FILE* fp=fopen(antislash(save),"wb");
  708.                     if (fp) fclose(fp);
  709.                     if (opt->log!=NULL) {
  710.                       fspc(opt->log,"warning"); fprintf(opt->log,"File must have been erased by user, ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  711.                     }
  712.                   }
  713.                 }
  714.               }
  715.             }
  716.           }
  717.         }
  718.         //
  719.       } else
  720. #if HTS_FAST_CACHE
  721.         hash_pos_return=0;
  722. #else
  723.         a=NULL;
  724. #endif
  725.  
  726.       // Existe pas en cache, ou bien pas de cache prΘsent
  727. #if HTS_FAST_CACHE
  728.       if (hash_pos_return) {  // OK existe en cache (et donnΘes aussi)!
  729. #else
  730.       if (a!=NULL) {  // OK existe en cache (et donnΘes aussi)!
  731. #endif
  732.         if (cache->type==1) {   // cache prioritaire (pas de test if-modified..)
  733.                                // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302...
  734.           // lire dans le cache
  735.           if (!test)
  736.             back[p].r = cache_read(opt,cache,adr,fil,save, back[p].location_buffer);
  737.           else
  738.             back[p].r = cache_read(opt,cache,adr,fil,NULL, back[p].location_buffer);  // charger en tΩte uniquement du cache
  739.  
  740.           /* ensure correct location buffer set */
  741.           back[p].r.location=back[p].location_buffer;
  742.  
  743.           /* Interdiction taille par le wizard? --> dΘtruire */
  744.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  745.             if (!back_checksize(opt,&back[p],0)) {
  746.               back[p].status=0;  // FINI
  747.               back[p].r.statuscode=-1;
  748.               if (!back[p].testmode)
  749.                 strcpybuff(back[p].r.msg,"Cached file skipped (too big)");
  750.               else
  751.                 strcpybuff(back[p].r.msg,"Test: Cached file skipped  (too big)");
  752.               return 0;
  753.             }
  754.           }
  755.  
  756.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  757.             if ((opt->debug>0) && (opt->log!=NULL)) {
  758.               if (!test) {
  759.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  760.               } else {
  761.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  762.               }
  763.             }
  764.             back[p].r.notmodified=1;    // fichier non modifiΘ
  765.             back[p].status=0;  // OK prΩt
  766.  
  767.             // finalize transfer
  768.             if (!test) {
  769.               if (back[p].r.statuscode>0) {
  770.                 back_finalize(opt,cache,back,p);
  771.               }
  772.             }
  773.  
  774.             return 0;
  775.           } else {  // erreur
  776.             // effacer r
  777.             memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  778.             // et continuer (chercher le fichier)
  779.           }
  780.           
  781.         } else if (cache->type==2) {    // si en cache, demander de tester If-Modified-Since
  782.           htsblk* r=cache_header(opt,cache,adr,fil);
  783.  
  784.           /* Interdiction taille par le wizard? */
  785.           {
  786.             LLint save_totalsize=back[p].r.totalsize;
  787.             back[p].r.totalsize=r->totalsize;
  788.             if (!back_checksize(opt,&back[p],1)) {
  789.               r=NULL;
  790.               //
  791.               back[p].status=0;  // FINI
  792.               deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
  793.               if (!back[p].testmode)
  794.                 strcpybuff(back[p].r.msg,"File too big");
  795.               else
  796.                 strcpybuff(back[p].r.msg,"Test: File too big");
  797.               return 0;
  798.             }
  799.             back[p].r.totalsize=save_totalsize;
  800.           }
  801.           
  802.           if (r) {
  803.             if (r->statuscode==200) {     // uniquement des 200 (OK)
  804.               if (strnotempty(r->etag)) {  // ETag (RFC2616)
  805.                 /*
  806.                 - If both an entity tag and a Last-Modified value have been
  807.                 provided by the origin server, SHOULD use both validators in
  808.                 cache-conditional requests. This allows both HTTP/1.0 and
  809.                 HTTP/1.1 caches to respond appropriately.
  810.                 */
  811.                 if (strnotempty(r->lastmodified))
  812.                   sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r->etag,r->lastmodified);
  813.                 else
  814.                   sprintf(back[p].send_too,"If-None-Match: %s\r\n",r->etag);
  815.               }
  816.               else if (strnotempty(r->lastmodified))
  817.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r->lastmodified);
  818.               else if (strnotempty(cache->lastmodified))
  819.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  820.               
  821.               /* this is an update of a file */
  822.               if (strnotempty(back[p].send_too))
  823.                 back[p].is_update=1;
  824.               back[p].r.req.nocompression=1;   /* Do not compress when updating! */
  825.               
  826.             }
  827.             /* else if (strnotempty(cache->lastmodified))
  828.             sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  829.             */
  830.           }
  831. #if DEBUGCA
  832.           printf("..is modified test %s\n",back[p].send_too);
  833. #endif
  834.         } 
  835.         // Okay, pas trouvΘ dans le cache
  836.         // Et si le fichier existe sur disque?
  837.         // Pas dans le cache: fichier n'a pas ΘtΘ transfΘrΘ du tout, donc pas sur disque?
  838.       } else {
  839.         if (fexist(save)) {    // fichier existe? aghl!
  840.           LLint sz=fsize(save);
  841.           // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
  842.           // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
  843.           // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
  844.           // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
  845.           if ((ishtml(save) != 1) && (ishtml(back[p].url_fil)!=1)) {   // NON HTML (liens changΘs!!)
  846.             if (sz>0) {    // Fichier non vide? (question bΩte, sinon on transfert tout!)
  847.               if (strnotempty(cache->lastmodified)) {     /* pas de If-.. possible */
  848.                 /*if ( (!opt->http10) && (strnotempty(cache->lastmodified)) ) { */    /* ne pas forcer 1.0 */
  849. #if DEBUGCA
  850.                 printf("..if unmodified since %s size "LLintP"\n",cache->lastmodified,(LLint)sz);
  851. #endif
  852.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  853.                   fspc(opt->log,"debug"); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  854.                 }
  855.                 
  856.                 /* impossible - don't have etag or date
  857.                 if (strnotempty(back[p].r.etag)) {  // ETag (RFC2616)
  858.                 sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
  859.                 back[p].http11=1;    // En tΩte 1.1
  860.                 } else if (strnotempty(back[p].r.lastmodified)) {
  861.                 sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
  862.                 back[p].http11=1;    // En tΩte 1.1
  863.                 } else 
  864.                 */
  865.                 if (strlen(cache->lastmodified)) {
  866.                   sprintf(back[p].send_too,
  867.                     "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
  868.                     ,cache->lastmodified,(LLint)sz);
  869.                   back[p].http11=1;    // En tΩte 1.1
  870.                   back[p].range_req_size=sz;
  871.                   back[p].r.req.range_used=1;
  872.                   back[p].r.req.nocompression=1;
  873.                 } else {
  874.                   if ((opt->debug>0) && (opt->log!=NULL)) {
  875.                     fspc(opt->log,"warning"); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  876.                   }
  877.                 }
  878.                 
  879.               } else { 
  880.                 if ((opt->debug>0) && (opt->errlog!=NULL)) {
  881.                   fspc(opt->errlog,"warning");
  882.                   /*
  883.                   if (opt->http10)
  884.                   fprintf(opt->errlog,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
  885.                   else
  886.                   */
  887.                   fprintf(opt->errlog,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  888.                   test_flush;
  889.                 }
  890.                 /* Sinon requΩte normale... */
  891.                 back[p].http11=0;
  892.               }
  893.             } else if (opt->norecatch) {              // tester norecatch
  894.               filenote(save,NULL);       // ne pas purger tout de mΩme
  895.               back[p].status=0;  // OK prΩt
  896.               back[p].r.statuscode=-1;  // erreur
  897.               strcpybuff(back[p].r.msg,"Null-size file not recaught");
  898.               return 0;
  899.             }
  900.           } else {
  901.             if ((opt->debug>0) && (opt->errlog!=NULL)) {
  902.               fspc(opt->errlog,"warning");
  903.               fprintf(opt->errlog,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  904.               test_flush;
  905.             }
  906.             /* Sinon requΩte normale... */
  907.             back[p].http11=0;
  908.           }
  909.         }
  910.       }
  911.     }
  912.  
  913.  
  914.     {
  915.       ///htsblk r;   non directement dans la structure-rΘponse!
  916.       T_SOC soc;
  917.       
  918.       // ouvrir liaison, envoyer requΦte
  919.       // ne pas traiter ou recevoir l'en tΩte immΘdiatement
  920.       memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  921.       // recopier proxy
  922.       memcpy(&(back[p].r.req.proxy), &opt->proxy, sizeof(opt->proxy));
  923.       // et user-agent
  924.       strcpybuff(back[p].r.req.user_agent,opt->user_agent);
  925.       strcpybuff(back[p].r.req.lang_iso,opt->lang_iso);
  926.       back[p].r.req.user_agent_send=opt->user_agent_send;
  927.       // et http11
  928.       back[p].r.req.http11=back[p].http11;
  929.       back[p].r.req.nocompression=opt->nocompression;
  930.       back[p].r.req.nokeepalive=opt->nokeepalive;
  931.  
  932.       // mode ftp, court-circuit!
  933.       if (strfield(back[p].url_adr,"ftp://")) {
  934.         if (back[p].testmode) {
  935.           if ((opt->debug>1) && (opt->errlog!=NULL)) {
  936.             fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: forbidden test with ftp link for back_add"LF);
  937.           }
  938.           return -1;    // erreur pas de test permis
  939.         }
  940.         if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
  941.           back[p].status=1000;   // connexion ftp
  942. #if USE_BEGINTHREAD
  943.           launch_ftp(&(back[p]));
  944. #else
  945.           {
  946.             char nid[32];
  947.             sprintf(nid,"htsftp%d-in_progress.lock",p);
  948.             strcpybuff(back[p].location_buffer,fconcat(opt->path_log,nid));
  949.           }
  950.           launch_ftp(&(back[p]),back[p].location_buffer,opt->exec);
  951. #endif
  952.           return 0;
  953.         }
  954.       }
  955. #if HTS_USEOPENSSL
  956.       else if (SSL_is_available && strfield(back[p].url_adr,"https://")) {        // let's rock
  957.         back[p].r.ssl = 1;
  958.         // back[p].r.ssl_soc = NULL;
  959.         back[p].r.ssl_con = NULL;
  960.       }
  961. #endif
  962.       
  963.       if (!back_trylive(back, back_max, p)) {
  964. #if HTS_XGETHOST
  965. #if HDEBUG
  966.         printf("back_solve..\n");
  967. #endif
  968.         back[p].status=101;    // tentative de rΘsolution du nom de host
  969.         soc=INVALID_SOCKET;    // pas encore ouverte
  970.         back_solve(&back[p]);  // prΘparer
  971.         if (host_wait(&back[p])) {  // prΩt, par ex fichier ou dispo dans dns
  972. #if HDEBUG
  973.           printf("ok, dns cache ready..\n");
  974. #endif
  975.           soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  976.           if (soc==INVALID_SOCKET) {
  977.             back[p].status=0;  // fini, erreur
  978.           }
  979.         }
  980.         //
  981. #else
  982.         //
  983. #if CNXDEBUG
  984.         printf("XFopen..\n");
  985. #endif
  986.         
  987.         if (strnotempty(back[p].send_too))    // envoyer un if-modified-since
  988. #if HTS_XCONN
  989.           soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  990. #else
  991.         soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
  992. #endif
  993.         else
  994. #if HTS_XCONN
  995.           soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
  996. #else
  997.         soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
  998. #endif
  999. #endif
  1000.       } else {
  1001.         soc = back[p].r.soc;
  1002.  
  1003.         if ((opt->debug>1) && (opt->log!=NULL)) {
  1004.           fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): successfully linked #%d (%s)"LF, 
  1005.             back[p].r.debugid,
  1006.             back[p].url_adr); test_flush;
  1007.         }
  1008.       }
  1009.       
  1010.       if (opt->timeout>0) {    // gestion du opt->timeout
  1011.         back[p].timeout=opt->timeout;
  1012.         back[p].timeout_refresh=time_local();
  1013.       } else {
  1014.         back[p].timeout=-1;    // pas de gestion (default)
  1015.       }
  1016.       
  1017.       if (opt->rateout>0) {    // gestion d'un taux minimum de transfert tolΘrΘ
  1018.         back[p].rateout=opt->rateout;
  1019.         back[p].rateout_time=time_local();
  1020.       } else {
  1021.         back[p].rateout=-1;    // pas de gestion (default)
  1022.       }
  1023.  
  1024.       // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
  1025.       // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
  1026.       //if ((back[p].statuscode!=200) || (soc<0)) { // ERREUR HTTP/autre
  1027.  
  1028. #if CNXDEBUG
  1029. printf("Xfopen ok, poll..\n");
  1030. #endif
  1031.  
  1032. #if HTS_XGETHOST
  1033.     if (soc!=INVALID_SOCKET)
  1034.       if (back[p].status==101) {  // pas d'erreur
  1035.         if (!back[p].r.is_file)
  1036.           back[p].status=100;   // connexion en cours
  1037.         else
  1038.           back[p].status=1;     // fichier
  1039.       }
  1040.  
  1041. #else
  1042.       if (soc==INVALID_SOCKET) { // erreur socket
  1043.         back[p].status=0;    // FINI
  1044.         //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
  1045.         back[p].r.soc=INVALID_SOCKET;
  1046.       } else {
  1047.         if (!back[p].r.is_file)
  1048. #if HTS_XCONN
  1049.           back[p].status=100;   // connexion en cours
  1050. #else
  1051.           back[p].status=99;    // chargement en tΩte en cours
  1052. #endif
  1053.         else
  1054.           back[p].status=1;     // chargement fichier
  1055. #if BDEBUG==1
  1056.         printf("..loading header\n");
  1057. #endif
  1058.       }
  1059. #endif
  1060.       
  1061.     }
  1062.  
  1063.  
  1064.     // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
  1065.     // le lien est considΘrΘ comme traitΘ
  1066.     //if (back[p].soc<0)  // erreur
  1067.     //  return -1;
  1068.  
  1069.     return 0;
  1070.   } else {
  1071.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  1072.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: no space left in stack for back_add"LF);
  1073.     }
  1074.     return -1;    // plus de place
  1075.   }
  1076. }
  1077.  
  1078.  
  1079.  
  1080. #if HTS_XGETHOST
  1081. #if USE_BEGINTHREAD
  1082. // lancement multithread du robot
  1083. PTHREAD_TYPE Hostlookup(void* iadr_p) {
  1084.   char iadr[256];
  1085.   t_dnscache* cache=_hts_cache();  // adresse du cache
  1086.   t_hostent* hp;
  1087.   int error_found=0;
  1088.  
  1089.   // recopier (aprΦs id:pass)
  1090. #if DEBUGDNS 
  1091.   printf("resolv in background: %s\n",jump_identification(iadr_p));
  1092. #endif
  1093.   strcpybuff(iadr,jump_identification(iadr_p));
  1094.   // couper Θventuel :
  1095.   {
  1096.     char *a;
  1097.     if ( (a=jump_toport(iadr)) )
  1098.       *a='\0';          // get rid of it
  1099.   }
  1100.   freet(iadr_p);
  1101.  
  1102.   // attendre que le cache dns soit prΩt
  1103.   while(_hts_lockdns(-1));  // attendre libΘration
  1104.   _hts_lockdns(1);          // locker
  1105.   while(cache->n) {
  1106.     if (strcmp(cache->iadr,iadr)==0) {
  1107.       error_found=1;
  1108.     }
  1109.     cache=cache->n;    // calculer queue
  1110.   }
  1111.   if (strcmp(cache->iadr,iadr)==0) {
  1112.     error_found=1;
  1113.   }
  1114.  
  1115.   if (!error_found) {
  1116.     // en gros copie de hts_gethostbyname sans le return
  1117.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  1118.     if (cache->n!=NULL) {
  1119.       t_fullhostent fullhostent_buffer;
  1120.       strcpybuff(cache->n->iadr,iadr);
  1121.       cache->n->host_length=0;        /* pour le moment rien */
  1122.       cache->n->n=NULL;
  1123.       _hts_lockdns(0);          // dΘlocker
  1124.       
  1125.       /* resolve */
  1126. #if DEBUGDNS 
  1127.       printf("gethostbyname() in progress for %s\n",iadr);
  1128. #endif
  1129.       cache->n->host_length=-1;
  1130.       memset(cache->n->host_addr, 0, sizeof(cache->n->host_addr));
  1131.       hp=vxgethostbyname(iadr, &fullhostent_buffer);
  1132.       if (hp!=NULL) {
  1133.         memcpy(cache->n->host_addr, hp->h_addr, hp->h_length);
  1134.         cache->n->host_length = hp->h_length;
  1135.       }
  1136.     } else 
  1137.     _hts_lockdns(0);          // dΘlocker
  1138.   } else {
  1139. #if DEBUGDNS 
  1140.     printf("aborting resolv for %s (found)\n",iadr);
  1141. #endif
  1142.     _hts_lockdns(0);          // dΘlocker
  1143.   }
  1144.   // fin de copie de hts_gethostbyname
  1145.  
  1146. #if DEBUGDNS 
  1147.   printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
  1148. #endif
  1149.  
  1150.   return PTHREAD_RETURN;     /* _endthread implied  */
  1151. }
  1152. #endif
  1153.  
  1154. // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
  1155. // si c'est un fichier, la rΘsolution est immΘdiate
  1156. // idem pour ftp://
  1157. void back_solve(lien_back* back) {
  1158.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1159.   //## if (back->url_adr[0]!=lOCAL_CHAR) {  // qq chose α prΘparer
  1160.     char* a;
  1161.     if (!(back->r.req.proxy.active))
  1162.       a=back->url_adr;
  1163.     else
  1164.       a=back->r.req.proxy.name;
  1165.     a = jump_protocol(a);
  1166.     if (!hts_dnstest(a)) {   // non encore testΘ!..
  1167.       // inscire en thread
  1168. #if HTS_WIN
  1169.       // Windows
  1170. #if USE_BEGINTHREAD
  1171.       {
  1172.         char* p = calloct(strlen(a)+2,1);
  1173.         if (p) {
  1174.           strcpybuff(p,a);
  1175.           _beginthread( Hostlookup , 0, p );
  1176.         }
  1177.       }
  1178. #else
  1179.       /*t_hostent* h=*/
  1180.       /*hts_gethostbyname(a);*/  // calcul
  1181. #endif
  1182. #else
  1183. #if USE_BEGINTHREAD
  1184.         char* p = calloct(strlen(a)+2,1);
  1185.         if (p) {
  1186.           strcpybuff(p,a);
  1187.           _beginthread( Hostlookup , 0, p );
  1188.         }
  1189. #else
  1190.       // Sous Unix, le gethostbyname() est bloquant..
  1191.       /*t_hostent* h=*/
  1192.       /*hts_gethostbyname(a);*/  // calcul
  1193. #endif
  1194. #endif
  1195.     }
  1196.   }
  1197. }
  1198.  
  1199. // dΘtermine si le host a pu Ωtre rΘsolu
  1200. int host_wait(lien_back* back) {
  1201.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1202.   //## if (back->url_adr[0]!=lOCAL_CHAR) {
  1203.     if (!(back->r.req.proxy.active)) {
  1204.       return (hts_dnstest(back->url_adr));
  1205.     } else {
  1206.       return (hts_dnstest(back->r.req.proxy.name));      
  1207.     }
  1208.   } else return 1;    // prΩt, fichier local
  1209. }
  1210. #endif
  1211.  
  1212.  
  1213. // Θlimine les fichiers non html en backing (anticipation)
  1214. // cleanup non-html files in backing to save backing space
  1215. // and allow faster "save in cache" operation
  1216. // also cleanup keep-alive sockets and ensure that not too many sockets are being opened
  1217. void back_clean(httrackp* opt,cache_back* cache,lien_back* back,int back_max) {
  1218. #if HTS_ANALYSTE
  1219.   int oneMore = ( (_hts_in_html_parsing == 2 && opt->maxsoc >= 2) || (_hts_in_html_parsing == 1 && opt->maxsoc >= 4) ) ? 1 : 0;  // testing links
  1220. #endif
  1221.   int i;
  1222.   for(i=0;i<back_max;i++) {
  1223.     if (back[i].status == 0) {                                   // ready
  1224.       /* Check autoclean */
  1225.       if (!back[i].testmode) {                                   // not test mode
  1226.         if (strnotempty(back[i].url_sav)) {                      // filename exists
  1227.           if (back[i].r.is_write) {                              // not in memory (on disk, ready)
  1228.             if (back[i].r.size>0) {                              // size>0
  1229.               if (back[i].r.statuscode==200) {                   // HTTP "OK"
  1230.                 if (!is_hypertext_mime(back[i].r.contenttype)) { // not HTML/hypertext
  1231.                   if (!may_be_hypertext_mime(back[i].r.contenttype)) { // may NOT be parseable mime type
  1232.                     if (back[i].pass2_ptr) {
  1233.                       // finalize
  1234.                       // // back_finalize(opt,cache,back,i);
  1235.                       // stats
  1236.                       //HTS_STAT.stat_bytes+=back[i].r.size;
  1237.                       //HTS_STAT.stat_files++;
  1238.                       //if ( (!back[i].r.notmodified) && (opt->is_update) ) { 
  1239.                       //  HTS_STAT.stat_updated_files++;       // page modifiΘe
  1240.                       //}
  1241.                       //cache_mayadd(opt,cache,&back[i].r,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  1242.                       *back[i].pass2_ptr=-1;  // Done!
  1243.                       back_maydelete(back,opt,i);    // May delete backing entry
  1244.                       if ((opt->debug>0) && (opt->log!=NULL)) {
  1245.                         fspc(opt->log,"info"); fprintf(opt->log,"File successfully written in background: %s"LF,back[i].url_sav); test_flush;
  1246.                       }
  1247.                     }
  1248.                   }
  1249.                 }
  1250.               }
  1251.             }
  1252.           }
  1253.         }
  1254.       }
  1255.     } else if (back[i].status == -103) {                         // waiting (keep-alive)
  1256.       if (
  1257.         ! back[i].r.keep_alive
  1258.         || back[i].r.soc == INVALID_SOCKET
  1259.         || back[i].r.keep_alive_max < 1
  1260.         || time_local() >= back[i].ka_time_start + back[i].r.keep_alive_t
  1261.         ) {
  1262.         if ((opt->debug>0) && (opt->log!=NULL)) {
  1263.             fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): live socket closed #%d (%s)"LF, 
  1264.             back[i].r.debugid,
  1265.             back[i].url_adr);
  1266.             test_flush;
  1267.         }
  1268.         back_delete(back, i);    // delete backing entry
  1269.       }
  1270.     }
  1271.   }
  1272.   /* switch connections to live ones */
  1273.   for(i=0;i<back_max;i++) {
  1274.     if (back[i].status == 0) {                                   // ready
  1275.       if (back[i].r.soc != INVALID_SOCKET) {
  1276.         back_maydeletehttp(back, back_max, opt, i);
  1277.       }
  1278.       
  1279.     }
  1280.   }
  1281.   /* delete sockets if too many keep-alive'd sockets in background */
  1282.   if (opt->maxsoc > 0) {
  1283.     int max = opt->maxsoc + oneMore;
  1284.     int curr = back_nsoc_overall(back, back_max);
  1285.     if (curr > max) {
  1286.       if ((opt->debug>1) && (opt->log!=NULL)) {
  1287.         fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): deleting #%d sockets"LF, 
  1288.           curr - max); test_flush;
  1289.       }
  1290.     }
  1291.     for(i = 0 ; i < back_max && curr > max ; i++) {
  1292.       if (back[i].status == -103) {
  1293.         back_delete(back, i);    // delete backing entry
  1294.         curr--;
  1295.       }
  1296.     }
  1297.   }
  1298. }
  1299.  
  1300.  
  1301. // attente (gestion des buffers des sockets)
  1302. void back_wait(lien_back* back,int back_max,httrackp* opt,cache_back* cache,TStamp stat_timestart) {
  1303.   int i;
  1304.   T_SOC nfds=INVALID_SOCKET;
  1305.   fd_set fds,fds_c,fds_e;     // fds pour lecture, connect (write), et erreur
  1306.   int nsockets;     // nbre sockets
  1307.   LLint max_read_bytes;  // max bytes read per sockets
  1308.   struct timeval tv;
  1309.   int do_wait=0;
  1310.   int gestion_timeout=0;
  1311.   int busy_recv=0;     // pas de donnΘes pour le moment   
  1312.   int busy_state=0;    // pas de connexions
  1313.   int max_loop;  // nombre de boucles max α parcourir..
  1314. #if HTS_ANALYSTE
  1315.   int max_loop_chk=0;
  1316. #endif
  1317.  
  1318.  
  1319.   // max. number of loops
  1320.   max_loop=8;
  1321.  
  1322. #if 1
  1323.   // Cleanup the stack to save space!
  1324.   back_clean(opt,cache,back,back_max);
  1325. #endif
  1326.  
  1327.   // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
  1328.   do_wait=0;
  1329.   gestion_timeout=0;
  1330.   do {
  1331.     int max_c;
  1332.     busy_state=busy_recv=0;
  1333.  
  1334. #if 0
  1335.     check_rate(stat_timestart,opt->maxrate);    // vΘrifier taux de transfert
  1336. #endif
  1337.     // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
  1338.     FD_ZERO(&fds);
  1339.     FD_ZERO(&fds_c);
  1340.     FD_ZERO(&fds_e);
  1341.     nsockets=0;
  1342.     max_read_bytes=TAILLE_BUFFER;     // maximum bytes that can be read
  1343.     nfds=INVALID_SOCKET;
  1344.  
  1345.     max_c=1;
  1346.     for(i=0;i<back_max;i++) {
  1347.  
  1348.       // en cas de gestion du connect prΘemptif
  1349. #if HTS_XCONN
  1350.       if (back[i].status==100) {      // connexion
  1351.         do_wait=1;
  1352.  
  1353.         // noter socket write
  1354.         FD_SET(back[i].r.soc,&fds_c);
  1355.         
  1356.         // noter socket erreur
  1357.         FD_SET(back[i].r.soc,&fds_e);
  1358.  
  1359.         // calculer max
  1360.         if (max_c) {
  1361.           max_c=0;
  1362.           nfds=back[i].r.soc;
  1363.         } else if (back[i].r.soc>nfds) {
  1364.           // ID socket la plus ΘlevΘe
  1365.           nfds=back[i].r.soc;
  1366.         }
  1367.         
  1368.       } else
  1369. #endif
  1370. #if HTS_XGETHOST
  1371.       if (back[i].status==101) {      // attente
  1372.         // rien α faire..
  1373.       } else
  1374. #endif
  1375.       // poll pour la lecture sur les sockets
  1376.       if ((back[i].status>0) && (back[i].status<100)) {  // en rΘception http
  1377.             
  1378. #if BDEBUG==1
  1379.         //printf("....socket in progress: %d\n",back[i].r.soc);
  1380. #endif
  1381.         // non local et non ftp
  1382.         if (!back[i].r.is_file) {
  1383.         //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
  1384.           
  1385.           // vΘrification de sΘcuritΘ
  1386.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1387.             do_wait=1;
  1388.             
  1389.             // noter socket read
  1390.             FD_SET(back[i].r.soc,&fds);
  1391.             
  1392.             // noter socket error
  1393.             FD_SET(back[i].r.soc,&fds_e);
  1394.             
  1395.             // incrΘmenter nombre de sockets
  1396.             nsockets++;
  1397.  
  1398.             // calculer max
  1399.             if (max_c) {
  1400.               max_c=0;
  1401.               nfds=back[i].r.soc;
  1402.             } else if (back[i].r.soc>nfds) {
  1403.               // ID socket la plus ΘlevΘe
  1404.               nfds=back[i].r.soc;
  1405.             }
  1406.           } else {
  1407.             back[i].r.statuscode=-4;
  1408.             if (back[i].status==100)
  1409.               strcpybuff(back[i].r.msg,"Connect Error");
  1410.             else
  1411.               strcpybuff(back[i].r.msg,"Receive Error");
  1412.             back[i].status=0;  // terminΘ
  1413.             if ((opt->debug>0) && (opt->log!=NULL)) {
  1414.               fspc(opt->log,"warning"); fprintf(opt->log,"Unexpected socket error during pre-loop"LF); test_flush;
  1415.             }            
  1416.           }
  1417. #if WIDE_DEBUG
  1418.           else {
  1419.             DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
  1420.           }
  1421. #endif
  1422.           
  1423.         }
  1424.         
  1425.       }
  1426.     }    
  1427.     nfds++;
  1428.     
  1429.     if (do_wait) {  // attendre
  1430.       // temps d'attente max: 2.5 seconde
  1431.       tv.tv_sec=HTS_SOCK_SEC;
  1432.       tv.tv_usec=HTS_SOCK_MS;
  1433.       
  1434. #if BDEBUG==1
  1435.       printf("..select\n");
  1436. #endif
  1437.       
  1438.       // poller les sockets-attention au noyau sous Unix..
  1439. #if HTS_WIDE_DEBUG    
  1440.       DEBUG_W("select\n");
  1441. #endif
  1442.       select(nfds,&fds,&fds_c,&fds_e,&tv);
  1443. #if HTS_WIDE_DEBUG    
  1444.       DEBUG_W("select done\n");
  1445. #endif      
  1446.     }
  1447.     
  1448.     // maximum data which can be received for a socket, if limited
  1449.     if (nsockets) {
  1450.       if (opt->maxrate>0) {
  1451.         max_read_bytes = ( check_downloadable_bytes(opt->maxrate) / nsockets );
  1452.       }
  1453.     }
  1454.     if (!max_read_bytes)
  1455.       busy_recv=0;
  1456.     
  1457.     // recevoir les donnΘes arrivΘes
  1458.     for(i=0;i<back_max;i++) {
  1459.       
  1460.       if (back[i].status>0) {
  1461.         if (!back[i].r.is_file) {  // not file..
  1462.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1463.             int err=FD_ISSET(back[i].r.soc,&fds_e);
  1464.             if (err) {
  1465.               if (back[i].r.soc!=INVALID_SOCKET) {
  1466. #if HTS_DEBUG_CLOSESOCK
  1467.                 DEBUG_W("back_wait: deletehttp\n");
  1468. #endif
  1469.                 deletehttp(&back[i].r);
  1470.               }
  1471.               back[i].r.soc=INVALID_SOCKET;
  1472.               back[i].r.statuscode=-4;
  1473.               if (back[i].status==100)
  1474.                 strcpybuff(back[i].r.msg,"Connect Error");
  1475.               else
  1476.                 strcpybuff(back[i].r.msg,"Receive Error");
  1477.               if (back[i].status == -103) {     /* Keep-alive socket */
  1478.                 back_delete(back, i);
  1479.               } else {
  1480.                 back[i].status=0;  // terminΘ
  1481.               }
  1482.             }
  1483.           }
  1484.         }
  1485.       }
  1486.       
  1487.       // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
  1488.       if (back[i].status==100) {   // attendre connect
  1489.         int dispo=0;
  1490.         // vΘrifier l'existance de timeout-check
  1491.         if (!gestion_timeout)
  1492.           if (back[i].timeout>0)
  1493.             gestion_timeout=1;
  1494.           
  1495.           // connectΘ?
  1496.           dispo=FD_ISSET(back[i].r.soc,&fds_c);
  1497.           if (dispo) {    // ok connected!!
  1498.             busy_state=1;
  1499.             
  1500. #if HTS_USEOPENSSL
  1501.             /* SSL mode */
  1502.             if (SSL_is_available && back[i].r.ssl) {
  1503.               // handshake not yet launched
  1504.               if (!back[i].r.ssl_con) {
  1505.                 SSL_CTX_set_options(openssl_ctx, SSL_OP_ALL);
  1506.                 // new session
  1507.                 back[i].r.ssl_con = SSL_new(openssl_ctx);
  1508.                 if (back[i].r.ssl_con) {
  1509.                   SSL_clear(back[i].r.ssl_con);
  1510.                   if (SSL_set_fd(back[i].r.ssl_con, back[i].r.soc) == 1) {
  1511.                     SSL_set_connect_state(back[i].r.ssl_con);
  1512.                     back[i].status = 102;         /* handshake wait */
  1513.                   } else
  1514.                     back[i].r.statuscode=-6;
  1515.                 } else
  1516.                   back[i].r.statuscode=-6;
  1517.               }
  1518.               /* Error */
  1519.               if (back[i].r.statuscode == -6) {
  1520.                 strcpybuff(back[i].r.msg, "bad SSL/TLS handshake");
  1521.                 deletehttp(&back[i].r);
  1522.                 back[i].r.soc=INVALID_SOCKET;
  1523.                 back[i].r.statuscode=-5;
  1524.                 back[i].status=0;
  1525.               }
  1526.             }
  1527.             
  1528. #endif
  1529.  
  1530. #if BDEBUG==1
  1531.           printf("..connect ok on socket %d\n",back[i].r.soc);
  1532. #endif
  1533.           
  1534.           if ((back[i].r.soc != INVALID_SOCKET) && (back[i].status==100)) {
  1535.             /* limit nb. connections/seconds to avoid server overload */
  1536.             if (opt->maxconn>0) {
  1537.               Sleep(1000/opt->maxconn);
  1538.             }
  1539.             
  1540.             back[i].ka_time_start=time_local();
  1541.             if (back[i].timeout>0) {    // refresh timeout si besoin est
  1542.               back[i].timeout_refresh=back[i].ka_time_start;
  1543.             }
  1544.             if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1545.               back[i].rateout_time=back[i].ka_time_start;
  1546.             }
  1547.             // envoyer header
  1548.             //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0)    // vrai get
  1549.             HTS_STAT.stat_nrequests++;
  1550.             if (!back[i].head_request)
  1551.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1552.             else if (back[i].head_request==2)  // test en GET!
  1553.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1554.             else        // test!
  1555.               http_sendhead(opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1556.             back[i].status=99;  // attendre en tΩte maintenant
  1557.           }
  1558.         }
  1559.         
  1560.         // attente gethostbyname
  1561.       }
  1562. #if HTS_USEOPENSSL
  1563.       else if (SSL_is_available && back[i].status==102) {   // wait for SSL handshake
  1564.         /* SSL mode */
  1565.         if (back[i].r.ssl) {
  1566.           int conn_code;
  1567.           if ((conn_code = SSL_connect(back[i].r.ssl_con)) <= 0) {
  1568.             /* non blocking I/O, will retry */
  1569.             int err_code = SSL_get_error(back[i].r.ssl_con, conn_code);
  1570.             if (
  1571.               (err_code != SSL_ERROR_WANT_READ)
  1572.               &&
  1573.               (err_code != SSL_ERROR_WANT_WRITE)
  1574.               ) {
  1575.               char tmp[256];
  1576.               tmp[0]='\0';
  1577.               ERR_error_string(err_code, tmp);
  1578.               back[i].r.msg[0]='\0';
  1579.               strncatbuff(back[i].r.msg, tmp, sizeof(back[i].r.msg) - 2);
  1580.               if (!strnotempty(back[i].r.msg)) {
  1581.                 sprintf(back[i].r.msg, "SSL/TLS error %d", err_code);
  1582.               }
  1583.               deletehttp(&back[i].r);
  1584.               back[i].r.soc=INVALID_SOCKET;
  1585.               back[i].r.statuscode=-5;
  1586.               back[i].status=0;
  1587.             }
  1588.           } else {        /* got it! */
  1589.             back[i].status=100;       // back to waitconnect
  1590.           }
  1591.         } else {
  1592.           strcpybuff(back[i].r.msg, "unexpected SSL/TLS error");
  1593.           deletehttp(&back[i].r);
  1594.           back[i].r.soc=INVALID_SOCKET;
  1595.           back[i].r.statuscode=-5;
  1596.           back[i].status=0;
  1597.         }
  1598.         
  1599.       }
  1600. #endif
  1601. #if HTS_XGETHOST
  1602.       else if (back[i].status==101) {  // attendre gethostbyname
  1603. #if DEBUGDNS 
  1604.         //printf("status 101 for %s\n",back[i].url_adr);
  1605. #endif
  1606.  
  1607.         if (!gestion_timeout)
  1608.           if (back[i].timeout>0)
  1609.             gestion_timeout=1;
  1610.  
  1611.         if (host_wait(&back[i])) {    // prΩt
  1612.           back[i].status=100;        // attente connexion
  1613.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  1614.             back[i].timeout_refresh=time_local();
  1615.           }
  1616.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1617.             back[i].rateout_time=time_local();
  1618.           }
  1619.  
  1620.           back[i].r.soc=http_xfopen(0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
  1621.           if (back[i].r.soc==INVALID_SOCKET) {
  1622.             back[i].status=0;  // fini, erreur
  1623.             if (back[i].r.soc!=INVALID_SOCKET) {
  1624. #if HTS_DEBUG_CLOSESOCK
  1625.               DEBUG_W("back_wait(2): deletehttp\n");
  1626. #endif
  1627.               deletehttp(&back[i].r);
  1628.             }
  1629.             back[i].r.soc=INVALID_SOCKET;
  1630.             back[i].r.statuscode=-5;
  1631.             if (strnotempty(back[i].r.msg)==0) 
  1632.               strcpybuff(back[i].r.msg,"Unable to resolve host name");
  1633.           }
  1634.         }
  1635.         
  1636.  
  1637.       // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
  1638.       }
  1639. #endif
  1640. #if USE_BEGINTHREAD
  1641.       // ..rien α faire, c'est magic les threads
  1642. #else
  1643.       else if (back[i].status==1000) {  // en rΘception ftp
  1644.         if (!fexist(back[i].location_buffer)) {    // terminΘ
  1645.           FILE* fp;
  1646.           fp=fopen(fconcat(back[i].location_buffer,".ok"),"rb");
  1647.           if (fp) {
  1648.             int j=0;
  1649.             fscanf(fp,"%d ",&(back[i].r.statuscode));
  1650.             while(!feof(fp)) {
  1651.               int c = fgetc(fp);
  1652.               if (c!=EOF)
  1653.                 back[i].r.msg[j++]=c;
  1654.             }
  1655.             back[i].r.msg[j++]='\0';
  1656.             fclose(fp);
  1657.             remove(fconcat(back[i].location_buffer,".ok"));
  1658.             strcpybuff(fconcat(back[i].location_buffer,".ok"),"");
  1659.           } else {
  1660.             strcpybuff(back[i].r.msg,"Unknown ftp result, check if file is ok");
  1661.             back[i].r.statuscode=-1;
  1662.           }
  1663.           back[i].status=0;
  1664.           // finalize transfer
  1665.           if (back[i].r.statuscode>0) {
  1666.             back_finalize(opt,cache,back,i);
  1667.           }
  1668.         }
  1669.       }
  1670. #endif
  1671.       else if ((back[i].status>0) && (back[i].status<1000)) {  // en rΘception http
  1672.         int dispo=0;
  1673.         
  1674.         // vΘrifier l'existance de timeout-check
  1675.         if (!gestion_timeout)
  1676.           if (back[i].timeout>0)
  1677.             gestion_timeout=1;
  1678.           
  1679.           // donnΘes dispo?
  1680.           //## if (back[i].url_adr[0]!=lOCAL_CHAR)
  1681.           if (!back[i].r.is_file) {
  1682.             dispo=FD_ISSET(back[i].r.soc,&fds);
  1683.           }
  1684.           else
  1685.             dispo=1;
  1686.  
  1687.           // Check transfer rate!
  1688.           if (!max_read_bytes)
  1689.             dispo=0;                // limit transfer rate
  1690.           
  1691.           if (dispo) {    // donnΘes dispo
  1692.             LLint retour_fread;
  1693.             busy_recv=1;    // on rΘcupΦre encore
  1694. #if BDEBUG==1
  1695.             printf("..data available on socket %d\n",back[i].r.soc);
  1696. #endif
  1697.  
  1698.             
  1699.             // range size hack old location
  1700.  
  1701. #if HTS_DIRECTDISK
  1702.             // Court-circuit:
  1703.             // Peut-on stocker le fichier directement sur disque?
  1704.             // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
  1705.             if (back[i].status) {
  1706.               if (back[i].r.is_write==0) {  // mode mΘmoire
  1707.                 if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1708.                   if (!back[i].testmode) {  // pas mode test
  1709.                     if (strnotempty(back[i].url_sav)) {
  1710.                       if (strcmp(back[i].url_fil,"/robots.txt")) {
  1711.                         if (back[i].r.statuscode==200) {  // 'OK'
  1712.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1713.                             if (opt->getmode&2) {    // on peut ecrire des non html
  1714.                               back[i].r.is_write=1;    // Θcrire
  1715.                               if (back[i].r.compressed
  1716.                                 &&
  1717.                                 /* .gz are *NOT* depacked!! */
  1718.                                 (strfield(get_ext(back[i].url_sav),"gz") == 0)
  1719.                                 ) {
  1720.                                 back[i].tmpfile[0]='\0';
  1721.                                 strcpybuff(back[i].tmpfile,tempnam(NULL,"httrZ"));
  1722.                                 if (back[i].tmpfile[0])
  1723.                                   back[i].r.out=fopen(back[i].tmpfile,"wb");
  1724.                               } else {
  1725.                                 back[i].r.compressed=0;
  1726.                                 back[i].r.out=filecreate(back[i].url_sav);
  1727.                               }
  1728. #if HDEBUG
  1729.                               printf("direct-disk: %s\n",back[i].url_sav);
  1730. #endif
  1731.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1732.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1733.                               }
  1734.                               
  1735.                               if (back[i].r.out==NULL) {
  1736.                                 if (opt->errlog) {
  1737.                                   fspc(opt->errlog,"error");
  1738.                                   fprintf(opt->errlog,"Unable to save file %s"LF,back[i].url_sav);
  1739.                                   test_flush;
  1740.                                 }
  1741.                                 back[i].r.is_write=0;    // erreur, abandonner
  1742. #if HDEBUG
  1743.                                 printf("..error!\n");
  1744. #endif
  1745.                               }
  1746. #if HTS_WIN==0
  1747.                               else chmod(back[i].url_sav,HTS_ACCESS_FILE);      
  1748. #endif          
  1749.                             } else {  // on coupe tout!
  1750.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1751.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1752.                               }
  1753.                               back[i].status=0;  // terminΘ
  1754.                               if (!back[i].testmode)
  1755.                                 back[i].r.statuscode=-10;    // EUHH CANCEL
  1756.                               else
  1757.                                 back[i].r.statuscode=-10;    // "TEST OK"
  1758.                               if (back[i].r.soc!=INVALID_SOCKET) {
  1759. #if HTS_DEBUG_CLOSESOCK
  1760.                                 DEBUG_W("back_wait(3): deletehttp\n");
  1761. #endif
  1762.                                 deletehttp(&back[i].r);
  1763.                               }
  1764.                               back[i].r.soc=INVALID_SOCKET;
  1765.                             }
  1766.                           }
  1767.                         }
  1768.                       }
  1769.                     }
  1770.                   }
  1771.                 }
  1772.               }
  1773.             }
  1774. #endif              
  1775.  
  1776.             // rΘception de donnΘes depuis socket ou fichier
  1777.             if (back[i].status) {
  1778.               if (back[i].status==99)  // recevoir par bloc de lignes
  1779.                 retour_fread=http_xfread1(&(back[i].r),0);
  1780.               else if (back[i].status==98 || back[i].status==97) { // recevoir longueur chunk en hexa caractΦre par caractΦre
  1781.                 // backuper pour lire dans le buffer chunk
  1782.                 htsblk r;
  1783.                 memcpy(&r, &(back[i].r), sizeof(htsblk));
  1784.                 back[i].r.is_write=0;                   // mΘmoire
  1785.                 back[i].r.adr=back[i].chunk_adr;        // adresse
  1786.                 back[i].r.size=back[i].chunk_size;      // taille taille chunk
  1787.                 back[i].r.totalsize=-1;                 // total inconnu
  1788.                 back[i].r.out=NULL;
  1789.                 back[i].r.is_file=0;
  1790.                 //
  1791.                 // ligne par ligne
  1792.                 retour_fread=http_xfread1(&(back[i].r),-1);
  1793.                 // modifier et restaurer
  1794.                 back[i].chunk_adr=back[i].r.adr;        // adresse
  1795.                 back[i].chunk_size=back[i].r.size;      // taille taille chunk
  1796.                 memcpy(&(back[i].r), &r, sizeof(htsblk));    // restaurer vΘritable r
  1797.               }
  1798.               else if (back[i].is_chunk) {         // attention chunk, limiter taille α lire
  1799. #if CHUNKDEBUG==1
  1800.                 printf("read %d bytes\n",(int)min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1801. #endif
  1802.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1803.               } else              
  1804.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) max_read_bytes);
  1805.                 // retour_fread=http_fread1(&(back[i].r));
  1806.             } else
  1807.               retour_fread=-1;                    // interruption ou annulation interne (peut ne pas Ωtre une erreur)
  1808.             
  1809.             // Si rΘception chunk, tester si on est pas α la fin!
  1810.             if (back[i].status==1) {
  1811.               if (back[i].is_chunk) {     // attendre prochain chunk
  1812.                 if (back[i].r.size==back[i].r.totalsize) {      // fin chunk!
  1813.                   //printf("chunk end at %d\n",back[i].r.size);
  1814.                   back[i].status=98;  // prochain chunk
  1815.                   if (back[i].chunk_adr!=NULL) { freet(back[i].chunk_adr); back[i].chunk_adr=NULL; } back[i].chunk_size=0;
  1816.                   retour_fread=0;       // pas d'erreur
  1817. #if CHUNKDEBUG==1
  1818.                   printf("waiting for next chunk header (soc %d)..\n",back[i].r.soc);
  1819. #endif
  1820.                 }
  1821.               } else if (back[i].r.keep_alive) {
  1822.                 if (back[i].r.size==back[i].r.totalsize) {      // fin!
  1823.                   retour_fread=-1;       // end
  1824.                 }
  1825.               }
  1826.             }
  1827.             
  1828.             if (retour_fread < 0) {    // fin rΘception
  1829.               back[i].status=0;    // terminΘ
  1830.               if (back[i].r.soc!=INVALID_SOCKET) {
  1831. #if HTS_DEBUG_CLOSESOCK
  1832.                 DEBUG_W("back_wait(4): deletehttp\n");
  1833. #endif
  1834.                 /*KA deletehttp(&back[i].r);*/
  1835.                 back_maydeletehttp(back, back_max, opt, i);
  1836.               }
  1837.               /*KA back[i].r.soc=INVALID_SOCKET; */
  1838. #if CHUNKDEBUG==1
  1839.               if (back[i].is_chunk)
  1840.                 printf("must be the last chunk for %s (connection closed) - %d/%d\n",back[i].url_fil,back[i].r.size,back[i].r.totalsize);
  1841. #endif
  1842.               //if ((back[i].r.statuscode==-1) && (strnotempty(back[i].r.msg)==0)) {
  1843.               if ((back[i].r.statuscode<0) && (strnotempty(back[i].r.msg)==0)) {
  1844. #if HDEBUG
  1845.                 printf("error interruped: %s\n",back[i].r.adr);
  1846. #endif        
  1847.                 if (back[i].r.size>0)
  1848.                   strcatbuff(back[i].r.msg,"Interrupted transfer");
  1849.                 else
  1850.                   strcatbuff(back[i].r.msg,"No data (connection closed)");
  1851.                 back[i].r.statuscode=-4;
  1852.               }
  1853.  
  1854.               // finalize transfer
  1855.               if (back[i].r.statuscode>0) {
  1856.                 back_finalize(opt,cache,back,i);
  1857.               }
  1858.  
  1859.               if (back[i].r.totalsize>0) {    // tester totalsize
  1860.               //if ((back[i].r.totalsize>0) && (back[i].status==99)) {    // tester totalsize
  1861.                 if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1862.                   if (!opt->tolerant) {
  1863.                     //#if HTS_CL_IS_FATAL
  1864.                     if (back[i].r.adr) freet(back[i].r.adr); back[i].r.adr=NULL;
  1865.                     if (back[i].r.size<back[i].r.totalsize)
  1866.                       back[i].r.statuscode=-4;        // recatch
  1867.                     sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",(LLint)back[i].r.size,(LLint)back[i].r.totalsize);
  1868.                   } else {
  1869.                     //#else
  1870.                     // Un warning suffira..
  1871.                     if (cache->errlog!=NULL) {
  1872.                       fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1873.                     }
  1874.                     //#endif
  1875.                   }
  1876.                 }
  1877.               }
  1878. #if BDEBUG==1
  1879.               printf("transfer ok\n");
  1880. #endif
  1881.             } else if (retour_fread > 0) {    // pas d'erreur de rΘception et data
  1882.               if (back[i].timeout>0) {    // refresh timeout si besoin est
  1883.                 back[i].timeout_refresh=time_local();
  1884.               }
  1885.  
  1886.               // Traitement des en tΩtes chunks ou en tΩtes
  1887.               if (back[i].status==98 || back[i].status==97) {        // rΘception taille chunk en hexa (  aprΦs les en tΩtes, peut ne pas
  1888.                 if (back[i].chunk_size > 2   /* garbage trailer */
  1889.                   ||
  1890.                   (back[i].chunk_size == 2 && back[i].status==97)
  1891.                   ||
  1892.                   (back[i].chunk_size == 2 && !isspace(back[i].chunk_adr[0]))
  1893.                   ) {
  1894.                   int chunk_size=-1;
  1895.                   // Ωtre prΘsent)
  1896.                   if (back[i].chunk_adr[back[i].chunk_size-1]==10) {    // LF, fin ligne chunk
  1897.                     char chunk_data[64];
  1898.                     if (back[i].chunk_size<32) {      // pas trop gros
  1899.                       char* chstrip=back[i].chunk_adr;
  1900.                       back[i].chunk_adr[ back[i].chunk_size-1]='\0';    // octet nul 
  1901.                       // skip leading spaces or cr
  1902.                       while(isspace(*chstrip)) chstrip++;
  1903.                       chunk_data[0] = '\0';
  1904.                       strncatbuff(chunk_data, chstrip, sizeof(chunk_data) - 2);
  1905.                       // strip chunk-extension
  1906.                       while( (chstrip = strchr(chunk_data, ';'))) *chstrip='\0';
  1907.                       while( (chstrip = strchr(chunk_data, ' '))) *chstrip='\0';
  1908.                       while( (chstrip = strchr(chunk_data, '\r'))) *chstrip='\0';
  1909. #if CHUNKDEBUG==1
  1910.                       printf("chunk received and read: %s\n",chunk_data);
  1911. #endif
  1912.                       if (back[i].r.totalsize<0)
  1913.                         back[i].r.totalsize=0;        // initialiser α 0
  1914.                       if (back[i].status==98) {   // "real" chunk
  1915.                         if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
  1916.                           back[i].r.totalsize+=chunk_size;    // noter taille
  1917.                           back[i].r.adr=(char*) realloct(back[i].r.adr,(INTsys) back[i].r.totalsize + 1);
  1918.                           if (!back[i].r.adr) {
  1919.                             if (cache->errlog!=NULL) {
  1920.                               fprintf(cache->errlog,"Error: Not enough memory ("LLintP") for %s%s"LF,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1921.                             }
  1922.                           }
  1923. #if CHUNKDEBUG==1
  1924.                           printf("chunk length: %d - next total "LLintP":\n",(int)chunk_size,(LLint)back[i].r.totalsize);
  1925. #endif
  1926.                         } else {
  1927.                           if (cache->errlog!=NULL) {
  1928.                             fprintf(cache->errlog,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  1929.                           }
  1930.                         }
  1931.                       } else {
  1932.                         chunk_size=0;
  1933.                       }
  1934.                     } else {                                  
  1935.                       if (cache->errlog!=NULL) {
  1936.                         fprintf(cache->errlog,"Warning: Chunk too big ("LLintP") for %s%s"LF,(LLint)back[i].chunk_size,back[i].url_adr,back[i].url_fil);
  1937.                       }
  1938.                     }
  1939.                     
  1940.                     // ok, continuer sur le body
  1941.                     
  1942.                     // si chunk non nul continuer (ou commencer)
  1943.                     if (chunk_size > 0) {
  1944.                       back[i].status=1;     // continuer body    
  1945. #if CHUNKDEBUG==1
  1946.                       printf("waiting for body (chunk)\n");
  1947. #endif
  1948.                     } else {                // chunk nul, c'est la fin
  1949. #if CHUNKDEBUG==1
  1950.                       printf("chunk end, total: %d\n",back[i].r.size);
  1951. #endif
  1952.                       /* End */
  1953.                       //if (back[i].status==97) {
  1954.                       back[i].status=0;     // fin  
  1955.                       //}
  1956.  
  1957.                       // finalize transfer
  1958.                       back_finalize(opt,cache,back,i);
  1959.                       if (back[i].r.soc!=INVALID_SOCKET) {
  1960. #if HTS_DEBUG_CLOSESOCK
  1961.                         DEBUG_W("back_wait(5): deletehttp\n");
  1962. #endif
  1963.                         /* Error */
  1964.                         if (chunk_size < 0) {
  1965.                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1966.                           if (back[i].r.adr) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1967.                           back[i].r.statuscode=-1;
  1968.                           strcpybuff(back[i].r.msg,"Invalid chunk");
  1969.                         } else /* if chunk_size == 0 */ {
  1970.                           
  1971.                           /* Clear ending CRLF */
  1972.                           //if (back[i].status==98) {
  1973.                           //  back[i].status=97;  // next "empty chunk"
  1974.                           //  if (back[i].chunk_adr!=NULL) { freet(back[i].chunk_adr); back[i].chunk_adr=NULL; } back[i].chunk_size=0;
  1975.                           //} else {
  1976.                           
  1977.                           /* Tester totalsize en fin de chunk */
  1978.                           if ((back[i].r.totalsize>0)) {    // tester totalsize
  1979.                             if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1980. #if HTS_CL_IS_FATAL
  1981.                               if (back[i].r.adr) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1982.                               back[i].r.statuscode=-1;
  1983.                               strcpybuff(back[i].r.msg,"Incorrect length");
  1984. #else
  1985.                               // Un warning suffira..
  1986.                               if (cache->errlog!=NULL) {
  1987.                                 fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1988.                               }
  1989. #endif
  1990.                             }
  1991.                           }
  1992.                           
  1993.                           /* Oops, trailers! */
  1994.                           if (back[i].r.keep_alive_trailers) {
  1995.                             /* fixme (not yet supported) */
  1996.                           }
  1997.                           
  1998.                           //}
  1999.                           
  2000.                         }
  2001.                         
  2002.                         
  2003.                       }
  2004.                     }
  2005.                     
  2006.                     // effacer buffer (chunk en tete)
  2007.                     if (back[i].chunk_adr!=NULL) {
  2008.                       freet(back[i].chunk_adr);
  2009.                       back[i].chunk_adr=NULL;
  2010.                       back[i].chunk_size=0;
  2011.                     }
  2012.                   
  2013.                   } // chunk LF?
  2014.                 }  // taille buffer chunk>2
  2015.                 //
  2016.               } else if (back[i].status==99) {        // en tΩtes (avant le chunk si il est prΘsent)
  2017.                 //
  2018.                 if (back[i].r.size>=2) {
  2019.                   // double LF
  2020.                   if (
  2021.                     ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) 
  2022.                     ||
  2023.                     (back[i].r.adr[0] == '<')    /* bogus server */
  2024.                     ) {
  2025.                     char rcvd[2048];
  2026.                     int ptr=0;
  2027.                     int noFreebuff=0;
  2028.                     
  2029. #if BDEBUG==1
  2030.                     printf("..ok, header received\n");
  2031. #endif
  2032.                     
  2033.                     /* Hack for zero-length headers */
  2034.                     if (back[i].r.adr[0] != '<') {
  2035.                       
  2036.                       // ----------------------------------------
  2037.                       // traiter en-tΩte!
  2038.                       // status-line α rΘcupΘrer
  2039.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  2040.                       if (strnotempty(rcvd)==0) {
  2041.                         /* Bogus CRLF, OR recycled connection and trailing chunk CRLF */
  2042.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  2043.                       }
  2044.                       
  2045.                       // traiter status-line
  2046.                       treatfirstline(&back[i].r,rcvd);
  2047.                       
  2048. #if HDEBUG
  2049.                       printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
  2050. #endif
  2051.                       if (_DEBUG_HEAD) {
  2052.                         if (ioinfo) {
  2053.                           fprintf(ioinfo,"[%d] response for %s%s:\r\ncode=%d\r\n",
  2054.                             back[i].r.debugid, jump_identification(back[i].url_adr),back[i].url_fil,back[i].r.statuscode);
  2055.                           fprintfio(ioinfo,back[i].r.adr,">>> ");
  2056.                           fprintf(ioinfo,"\r\n");
  2057.                           fflush(ioinfo);
  2058.                         }                    // en-tΩte
  2059.                       }
  2060.                       
  2061.                       // header // ** !attention! HTTP/0.9 non supportΘ
  2062.                       do {
  2063.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);          
  2064. #if HDEBUG
  2065.                         printf("(buffer)>%s\n",rcvd);      
  2066. #endif
  2067.                         /*
  2068.                         if (_DEBUG_HEAD) {
  2069.                         if (ioinfo) {
  2070.                         fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);      
  2071.                         fflush(ioinfo);
  2072.                         }
  2073.                         }
  2074.                         */
  2075.                         
  2076.                         if (strnotempty(rcvd))
  2077.                           treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd);  // traiter
  2078.                         
  2079.                         // parfois les serveurs buggΘs renvoient un content-range avec un 200
  2080.                         if (back[i].r.statuscode==200)  // 'OK'
  2081.                           if (strfield(rcvd,"content-range:"))  // Avec un content-range: relisez les RFC..
  2082.                             back[i].r.statuscode=206;    // FORCER A 206 !!!!!
  2083.                           
  2084.                       } while(strnotempty(rcvd));
  2085.                       // ----------------------------------------                    
  2086.  
  2087.                       // libΘrer mΘmoire  -- aprΦs! --
  2088.                       if (back[i].r.adr!=NULL) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  2089.                     } else {
  2090.                       // assume text/html, OK
  2091.                       treatfirstline(&back[i].r, back[i].r.adr);
  2092.                       noFreebuff=1;
  2093.                     }
  2094.                       
  2095.                   
  2096.                     
  2097.                     /* 
  2098.                     Status code and header-response hacks
  2099.                     */
  2100.  
  2101.                     
  2102.                     // Check response : 203 == 200
  2103.                     if (back[i].r.statuscode==203) {  // 'Non-Authoritative Information'
  2104.                       back[i].r.statuscode=200;       // forcer "OK"
  2105.                     } else if (back[i].r.statuscode == 100) {
  2106.                       back[i].status=99;
  2107.                       back[i].r.size=0;
  2108.                       back[i].r.totalsize=0;
  2109.                       back[i].chunk_size=0;
  2110.                       back[i].r.statuscode=-1;
  2111.                       back[i].r.msg[0]='\0';
  2112.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2113.                         fspc(opt->log,"debug"); fprintf(opt->log,"Status 100 detected for %s%s, continuing headers"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2114.                       }
  2115.                       continue;
  2116.                     }
  2117.                     
  2118.                     /*
  2119.                     Solve "false" 416 problems
  2120.                     */
  2121.                     if (back[i].r.statuscode==416) {  // 'Requested Range Not Satisfiable'
  2122.                       // Example:
  2123.                       // Range: bytes=2830-
  2124.                       // ->
  2125.                       // Content-Range: bytes */2830
  2126.                       if (back[i].range_req_size == back[i].r.crange) {
  2127.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2128.                         back[i].status=0;    // READY
  2129.                         back[i].r.size=back[i].r.totalsize=back[i].range_req_size;
  2130.                         filenote(back[i].url_sav,NULL);
  2131.                         back[i].r.statuscode=304;     // NOT MODIFIED
  2132.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  2133.                           fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (good 416 message), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2134.                         }
  2135.                       }
  2136.                     }
  2137.                     
  2138.                     // transform 406 into 200 ; we'll catch embedded links inside the choice page
  2139.                     if (back[i].r.statuscode==406) {  // 'Not Acceptable'
  2140.                       back[i].r.statuscode=200;
  2141.                     }
  2142.  
  2143.                     // Various hacks to limit re-transfers when updating a mirror
  2144.                     // Force update if same size detected
  2145.                     if (opt->sizehack) {
  2146.                       // We already have the file
  2147.                       // and ask the remote server for an update
  2148.                       // Some servers, especially dynamic pages severs, always
  2149.                       // answer that the page has been modified since last visit
  2150.                       // And answer with a 200 (OK) response, and the same page
  2151.                       // If the size is the same, and the option has been set, we assume
  2152.                       // that the file is identical - and therefore let's break the connection
  2153.                       if (back[i].is_update) {          // mise α jour
  2154.                         if (back[i].r.statuscode==200 && !back[i].testmode) {  // 'OK'
  2155.                           htsblk r = cache_read(opt,cache,back[i].url_adr,back[i].url_fil,NULL,NULL);    // lire entrΘe cache
  2156.                           if (r.statuscode == 200) {  // OK pas d'erreur cache
  2157.                             LLint len1,len2;
  2158.                             len1=r.totalsize;
  2159.                             len2=back[i].r.totalsize;
  2160.                             if (r.size>0)
  2161.                               len1=r.size;
  2162.                             if (len1>0) {
  2163.                               if (len1 == len2) {             // tailles identiques
  2164.                                 back[i].r.statuscode=304;     // forcer NOT MODIFIED
  2165.                                 deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2166.                                 if ((opt->debug>1) && (opt->log!=NULL)) {
  2167.                                   fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2168.                                 }
  2169.                               }
  2170.                             }
  2171.                           } else {
  2172.                             if (opt->errlog!=NULL) {
  2173.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"File seems complete (same size), but there was a cache read error: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2174.                             }
  2175.                           }
  2176.                           if (r.adr) {
  2177.                             freet(r.adr);
  2178.                           }
  2179.                         }
  2180.                       }
  2181.                     }
  2182.                     
  2183.                     // Various hacks to limit re-transfers when updating a mirror
  2184.                     // Detect already downloaded file (with another browser, for example)
  2185.                     if (opt->sizehack) {
  2186.                       if (!back[i].is_update) {          // mise α jour
  2187.                         if (back[i].r.statuscode==200 && !back[i].testmode) {  // 'OK'
  2188.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // not HTML
  2189.                             if (strnotempty(back[i].url_sav)) {  // target found
  2190.                               int size = fsize(back[i].url_sav);  // target size
  2191.                               if (size >= 0) {
  2192.                                 if (back[i].r.totalsize == size) {  // same size!
  2193.                                   deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2194.                                   back[i].status=0;    // READY
  2195.                                   back[i].r.size=back[i].r.totalsize;
  2196.                                   filenote(back[i].url_sav,NULL);
  2197.                                   back[i].r.statuscode=304;     // NOT MODIFIED
  2198.                                   if ((opt->debug>1) && (opt->log!=NULL)) {
  2199.                                     fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size file discovered), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2200.                                   }
  2201.                                 }
  2202.                               }
  2203.                             }
  2204.                           }
  2205.                         }
  2206.                       }
  2207.                     }
  2208.                     
  2209.                     // Various hacks to limit re-transfers when updating a mirror
  2210.                     // Detect bad range: header
  2211.                     if (opt->sizehack) {
  2212.                       // We have request for a partial file (with a 'Range: NNN-' header)
  2213.                       // and received a complete file notification (200), with 'Content-length: NNN'
  2214.                       // it might be possible that we had the complete file
  2215.                       // this is the case in *most* cases, so break the connection
  2216.                       if (back[i].r.is_write==0) {  // mode mΘmoire
  2217.                         if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  2218.                           if (!back[i].testmode) {  // pas mode test
  2219.                             if (strnotempty(back[i].url_sav)) {
  2220.                               if (strcmp(back[i].url_fil,"/robots.txt")) {
  2221.                                 if (back[i].r.statuscode==200) {  // 'OK'
  2222.                                   if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  2223.                                     if (back[i].r.statuscode==200) {      // "OK"
  2224.                                       if (back[i].range_req_size>0) {     // but Range: requested
  2225.                                         if (back[i].range_req_size == back[i].r.totalsize) {    // And same size
  2226. #if HTS_DEBUG_CLOSESOCK
  2227.                                           DEBUG_W("back_wait(skip_range): deletehttp\n");
  2228. #endif
  2229.                                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2230.                                           back[i].status=0;    // READY
  2231.                                           back[i].r.size=back[i].r.totalsize;
  2232.                                           filenote(back[i].url_sav,NULL);
  2233.                                           back[i].r.statuscode=304;     // NOT MODIFIED
  2234.                                           if ((opt->debug>1) && (opt->log!=NULL)) {
  2235.                                             fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (reget failed), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2236.                                           }
  2237.                                         }
  2238.                                       }
  2239.                                     }
  2240.                                     
  2241.                                   }
  2242.                                 }
  2243.                               }
  2244.                             }
  2245.                           }
  2246.                         }
  2247.                       }
  2248.                     }
  2249.                     // END - Various hacks to limit re-transfers when updating a mirror
  2250.  
  2251.                     /* 
  2252.                     End of status code and header-response hacks
  2253.                     */
  2254.  
  2255.                     
  2256.                     
  2257.                     /* Interdiction taille par le wizard? */
  2258.                     if (back[i].r.soc!=INVALID_SOCKET) {
  2259.                       if (!back_checksize(opt,&back[i],1)) {
  2260.                         back[i].status=0;  // FINI
  2261.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2262.                         if (!back[i].testmode)
  2263.                           strcpybuff(back[i].r.msg,"File too big");
  2264.                         else
  2265.                           strcpybuff(back[i].r.msg,"Test: File too big");
  2266.                       }
  2267.                     }
  2268.                     
  2269.                     /* sinon, continuer */
  2270.                     /* if (back[i].r.soc!=INVALID_SOCKET) {   // ok rΘcupΘrer body? */
  2271.                     // head: terminΘ
  2272.                     if (back[i].head_request) {
  2273.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2274.                         fspc(opt->log,"debug"); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2275.                       }
  2276. #if HTS_DEBUG_CLOSESOCK
  2277.                       DEBUG_W("back_wait(head request): deletehttp\n");
  2278. #endif
  2279.                       // Couper connexion
  2280.                       if (!back[i].http11) {    /* NO KA */
  2281.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2282.                       }
  2283.                       back[i].status=0;  // terminΘ
  2284.                     }
  2285.                     // traiter une Θventuelle erreur 304 (cache α jour utilisable)
  2286.                     else if (back[i].r.statuscode==304) {  // document α jour dans le cache
  2287.                       // lire dans le cache
  2288.                       // ** NOTE: pas de vΘrif de la taille ici!!
  2289. #if HTS_DEBUG_CLOSESOCK
  2290.                       DEBUG_W("back_wait(file is not modified): deletehttp\n");
  2291. #endif
  2292.                       /* clear everything but connection: switch, close, and reswitch */
  2293.                       {
  2294.                         htsblk tmp;
  2295.                         memset(&tmp, 0, sizeof(tmp));
  2296.                         back_connxfr(&back[i].r, &tmp);
  2297.                         back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav,back[i].location_buffer);
  2298.                         back[i].r.location=back[i].location_buffer;
  2299.                         back_connxfr(&tmp,&back[i].r);
  2300.                       }
  2301.  
  2302.                       // hack:
  2303.                       // In case of 'if-unmodified-since' hack, a 304 status can be sent
  2304.                       // then, force 'ok' status
  2305.                       if (back[i].r.statuscode == -1) {
  2306.                         if (fexist(back[i].url_sav)) {
  2307.                           back[i].r.statuscode=200;     // OK
  2308.                           strcpybuff(back[i].r.msg, "OK (cached)");
  2309.                           back[i].r.is_file=1;
  2310.                           back[i].r.totalsize = back[i].r.size = fsize(back[i].url_sav);
  2311.                           get_httptype(back[i].r.contenttype, back[i].url_sav, 1);
  2312.                           if ((opt->debug>0) && (opt->log!=NULL)) {
  2313.                             fspc(opt->log,"debug"); fprintf(opt->log,"Not-modified status without cache guessed: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2314.                           }
  2315.                         }
  2316.                       }
  2317.  
  2318.                       // Status is okay?
  2319.                       if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
  2320.                         back[i].status=0;         // OK prΩt
  2321.                         back[i].r.notmodified=1;  // NON modifiΘ!
  2322.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  2323.                           fspc(opt->log,"debug"); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2324.                         }
  2325.  
  2326.                         // finalize
  2327.                         if (back[i].r.statuscode>0) {
  2328.                           back_finalize(opt,cache,back,i);
  2329.                         }
  2330.                         
  2331. #if DEBUGCA
  2332.                         printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
  2333. #endif
  2334.                         
  2335.                         //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  2336.                       } else {  // erreur
  2337.                         back[i].status=0;  // terminΘ
  2338.                         //printf("erreur cache\n");
  2339.                         
  2340.                       } 
  2341.                       
  2342. /********** NO - must complete the body! ********** */
  2343. #if 0
  2344.                     } else if ((back[i].r.statuscode==301)
  2345.                       || (back[i].r.statuscode==302)
  2346.                       || (back[i].r.statuscode==303)
  2347.                       || (back[i].r.statuscode==307)
  2348.                       || (back[i].r.statuscode==412)
  2349.                       || (back[i].r.statuscode==416)
  2350.                       ) {   // Ne pas prendre le html, erreurs connues et gΘrΘes
  2351. #if HTS_DEBUG_CLOSESOCK
  2352.                       DEBUG_W("back_wait(301,302,303,307,412,416..): deletehttp\n");
  2353. #endif
  2354.                       // Couper connexion
  2355.                       /*KA deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;*/
  2356.                       back_maydeletehttp(back, back_max, opt, i);
  2357.  
  2358.                       back[i].status=0;  // terminΘ
  2359.                       // finalize
  2360.                       if (back[i].r.statuscode>0) {
  2361.                         back_finalize(opt,cache,back,i);
  2362.                       }
  2363. #endif
  2364. /********** **************************** ********** */
  2365.                     } else {    // il faut aller le chercher
  2366.                       
  2367.                       // effacer buffer (requΦte)
  2368.                       if (!noFreebuff) {
  2369.                         if (back[i].r.adr!=NULL) {
  2370.                           freet(back[i].r.adr);
  2371.                           back[i].r.adr=NULL;
  2372.                         }
  2373.                         back[i].r.size=0;
  2374.                       }
  2375.                       
  2376.                       // traiter 206 (partial content)
  2377.                       // xxc SI CHUNK VERIFIER QUE CA MARCHE??
  2378.                       if (back[i].r.statuscode==206) {  // on nous envoie un morceau (la fin) coz une partie sur disque!
  2379.                         LLint sz=fsize(back[i].url_sav);
  2380. #if HDEBUG
  2381.                         printf("partial content: "LLintP" on disk..\n",(LLint)sz);
  2382. #endif
  2383.                         if (sz>=0) {
  2384.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  2385.                             if (opt->getmode&2) {    // on peut ecrire des non html  **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
  2386.                               filenote(back[i].url_sav,NULL);    // noter fichier comme connu
  2387.                               back[i].r.out=fopen(fconv(back[i].url_sav),"ab");  // append
  2388.                               if (back[i].r.out) {
  2389.                                 back[i].r.is_write=1;    // Θcrire
  2390.                                 back[i].r.size=sz;    // dΘja Θcrit
  2391.                                 back[i].r.statuscode=200;  // Forcer 'OK'
  2392.                                 if (back[i].r.totalsize>0)
  2393.                                   back[i].r.totalsize+=sz;    // plus en fait
  2394.                                 fseek(back[i].r.out,0,SEEK_END);  // α la fin
  2395. #if HDEBUG
  2396.                                 printf("continue interrupted file\n");
  2397. #endif
  2398.                               } else {    // On est dans la m**
  2399.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2400.                                 strcpybuff(back[i].r.msg,"Can not open partial file");
  2401.                               }
  2402.                             }
  2403.                           } else {    // mΘmoire
  2404.                             FILE* fp=fopen(fconv(back[i].url_sav),"rb");
  2405.                             if (fp) {
  2406.                               LLint alloc_mem=sz + 1;
  2407.                               if (back[i].r.totalsize>0)
  2408.                                 alloc_mem+=back[i].r.totalsize;            // AJOUTER RESTANT!
  2409.                               if ( (back[i].r.adr=(char*) malloct((INTsys) alloc_mem)) ) {
  2410.                                 back[i].r.size=sz;
  2411.                                 if (back[i].r.totalsize>0)
  2412.                                   back[i].r.totalsize+=sz;    // plus en fait
  2413.                                 if (( fread(back[i].r.adr,1,(INTsys)sz,fp)) != sz) {
  2414.                                   back[i].status=0;  // terminΘ (voir plus loin)
  2415.                                   strcpybuff(back[i].r.msg,"Can not read partial file");
  2416.                                 } else {
  2417.                                   back[i].r.statuscode=200;  // Forcer 'OK'
  2418. #if HDEBUG
  2419.                                   printf("continue in mem interrupted file\n");
  2420. #endif
  2421.                                 }
  2422.                               } else {
  2423.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2424.                                 strcpybuff(back[i].r.msg,"No memory for partial file");
  2425.                               }
  2426.                               fclose(fp);
  2427.                             } else {  // Argh.. 
  2428.                               back[i].status=0;  // terminΘ (voir plus loin)
  2429.                               strcpybuff(back[i].r.msg,"Can not open partial file");
  2430.                             }
  2431.                           }
  2432.                         } else {    // Non trouvΘ??
  2433.                           back[i].status=0;  // terminΘ (voir plus loin)
  2434.                           strcpybuff(back[i].r.msg,"Can not find partial file");
  2435.                         }
  2436.                         // Erreur?
  2437.                         if (back[i].status==0) {
  2438.                           if (back[i].r.soc!=INVALID_SOCKET) {
  2439. #if HTS_DEBUG_CLOSESOCK
  2440.                             DEBUG_W("back_wait(206 solve problems): deletehttp\n");
  2441. #endif
  2442.                             deletehttp(&back[i].r);
  2443.                           }
  2444.                           back[i].r.soc=INVALID_SOCKET;
  2445.                           //back[i].r.statuscode=206;  ????????
  2446.                           back[i].r.statuscode=-5;
  2447.                           if (strnotempty(back[i].r.msg))
  2448.                             strcpybuff(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
  2449.                         }
  2450.                       }
  2451.                       
  2452.                       if (back[i].status!=0) {  // non terminΘ (erreur)
  2453.                         if (!back[i].testmode) {    // fichier normal
  2454.                           
  2455.                           if (back[i].r.empty && back[i].r.statuscode==200) {  // empty response
  2456.                             // Couper connexion
  2457.                             deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2458.                             back[i].status=0;  // terminΘ
  2459.                             if ( (back[i].r.adr=(char*) malloct((INTsys) 2)) ) {
  2460.                               back[i].r.adr[0] = 0;
  2461.                             }
  2462.                             back_finalize(opt,cache,back,i);
  2463.                           }
  2464.                           else if (!back[i].r.is_chunk) {    // pas de chunk
  2465.                             //if (back[i].r.http11!=2) {    // pas de chunk
  2466.                             back[i].is_chunk=0;
  2467.                             back[i].status=1;     // start body
  2468.                           } else {
  2469. #if CHUNKDEBUG==1
  2470.                             printf("chunk encoding detected %s..\n",back[i].url_fil);
  2471. #endif
  2472.                             back[i].is_chunk=1;
  2473.                             back[i].chunk_adr=NULL;
  2474.                             back[i].chunk_size=0;
  2475.                             back[i].status=98;    // start body wait chunk
  2476.                             back[i].r.totalsize=0;   /* devalidate size! (rfc) */
  2477.                           }
  2478.                           if (back[i].rateout>0) {
  2479.                             back[i].rateout_time=time_local();  // refresh pour transfer rate
  2480.                           }
  2481. #if HDEBUG
  2482.                           printf("(buffer) start body!\n");
  2483. #endif
  2484.                         } else {     // mode test, ne pas passer en 1!!
  2485.                           back[i].status=0;    // READY
  2486. #if HTS_DEBUG_CLOSESOCK
  2487.                           DEBUG_W("back_wait(test ok): deletehttp\n");
  2488. #endif
  2489.                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2490.                           if (back[i].r.statuscode==200) {
  2491.                             strcpybuff(back[i].r.msg,"Test: OK");
  2492.                             back[i].r.statuscode=-10;    // test rΘussi
  2493.                           }
  2494.                           else {    // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
  2495.                             char tempo[1000];
  2496.                             strcpybuff(tempo,back[i].r.msg);
  2497.                             strcpybuff(back[i].r.msg,"Test: ");
  2498.                             strcatbuff(back[i].r.msg,tempo);
  2499.                           }
  2500.                           
  2501.                         }
  2502.                       }
  2503.                       
  2504.                       } 
  2505.                       
  2506.                       /*}*/
  2507.                       
  2508.                   }  // si LF
  2509.                 }  // r.size>2
  2510.               }  // si == 99
  2511.               
  2512.             } // si pas d'erreurs
  2513. #if BDEBUG==1
  2514.             printf("bytes overall: %d\n",back[i].r.size);
  2515. #endif
  2516.           }  // donnΘes dispo
  2517.           
  2518.           // en cas d'erreur cl, supprimer Θventuel fichier sur disque
  2519. #if HTS_REMOVE_BAD_FILES
  2520.           if (back[i].status<0) {
  2521.             if (!back[i].testmode) {    // pas en test
  2522.               remove(back[i].url_sav);    // Θliminer fichier (endommagΘ)
  2523.               //printf("&& %s\n",back[i].url_sav);
  2524.             }
  2525.           }
  2526. #endif
  2527.  
  2528.           /* funny log for commandline users */
  2529.           //if (!opt->quiet) {  
  2530.           // petite animation
  2531.           if (opt->verbosedisplay==1) {
  2532.             if (back[i].status==0) {
  2533.               if (back[i].r.statuscode==200)
  2534.                 printf("* %s%s ("LLintP" bytes) - OK"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size);
  2535.               else
  2536.                 printf("* %s%s ("LLintP" bytes) - %d"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size,back[i].r.statuscode);
  2537.               fflush(stdout);
  2538.             }
  2539.           }
  2540.           //}
  2541.           
  2542.  
  2543.       } // status>0
  2544.     }  // for
  2545.     
  2546.     // vΘrifier timeouts
  2547.     if (gestion_timeout) {
  2548.       TStamp act;
  2549.       act=time_local();    // temps en secondes
  2550.       for(i=0;i<back_max;i++) {
  2551.         if (back[i].status>0) {  // rΘception/connexion/..
  2552.           if (back[i].timeout>0) {
  2553.             //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
  2554.             if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
  2555.               if (back[i].r.soc!=INVALID_SOCKET) {
  2556. #if HTS_DEBUG_CLOSESOCK
  2557.                 DEBUG_W("back_wait(timeout): deletehttp\n");
  2558. #endif
  2559.                 deletehttp(&back[i].r);
  2560.               }
  2561.               back[i].r.soc=INVALID_SOCKET;
  2562.               back[i].r.statuscode=-2;
  2563.               if (back[i].status==100)
  2564.                 strcpybuff(back[i].r.msg,"Connect Time Out");
  2565.               else if (back[i].status==101)
  2566.                 strcpybuff(back[i].r.msg,"DNS Time Out");
  2567.               else
  2568.                 strcpybuff(back[i].r.msg,"Receive Time Out");
  2569.               back[i].status=0;  // terminΘ
  2570.             } else if ((back[i].rateout>0) && (back[i].status<99)) {
  2571.               if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) {   // checker au bout de 15s
  2572.                 if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) {  // trop lent
  2573.                   back[i].status=0;  // terminΘ
  2574.                   if (back[i].r.soc!=INVALID_SOCKET) {
  2575. #if HTS_DEBUG_CLOSESOCK
  2576.                     DEBUG_W("back_wait(rateout): deletehttp\n");
  2577. #endif
  2578.                     deletehttp(&back[i].r);
  2579.                   }
  2580.                   back[i].r.soc=INVALID_SOCKET;
  2581.                   back[i].r.statuscode=-3;
  2582.                   strcpybuff(back[i].r.msg,"Transfer Rate Too Low");
  2583.                 }
  2584.               }
  2585.             }
  2586.           }
  2587.         }
  2588.       }
  2589.     }
  2590.     max_loop--;
  2591. #if HTS_ANALYSTE
  2592.     max_loop_chk++;
  2593. #endif
  2594.   } while((busy_state) && (busy_recv) && (max_loop>0));
  2595. #if HTS_ANALYSTE
  2596.   if ((!busy_recv) && (!busy_state)) {
  2597.     if (max_loop_chk>=1) {
  2598.       Sleep(10);    // un tite pause pour Θviter les lag..
  2599.     }
  2600.   }
  2601. #endif
  2602. }
  2603.  
  2604. int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
  2605.   LLint size_to_test;
  2606.   if (check_only_totalsize)
  2607.     size_to_test=eback->r.totalsize;
  2608.   else
  2609.     size_to_test=max(eback->r.totalsize,eback->r.size);
  2610.   if (size_to_test>=0) {
  2611.     
  2612.     /* Interdiction taille par le wizard? */
  2613.     if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,(eback->r.totalsize+1023)/1024)==-1) {
  2614.       return 0;     /* interdit */
  2615.     }                     
  2616.     
  2617.     /* vΘrifier taille classique (heml et non html) */
  2618.     if ((istoobig(size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
  2619.       return 0;     /* interdit */
  2620.     }
  2621.   }
  2622.   return 1;
  2623. }
  2624.  
  2625.  
  2626. // octets transfΘrΘs + add
  2627. LLint back_transfered(LLint nb,lien_back* back,int back_max) {
  2628.   int i;
  2629.   // ajouter octets en instance
  2630.   for(i=0;i<back_max;i++)
  2631.     if ((back[i].status>0) && (back[i].status<99))
  2632.       nb+=back[i].r.size;
  2633.   return nb;      
  2634. }
  2635.  
  2636. // infos backing
  2637. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2638. void back_info(lien_back* back,int i,int j,FILE* fp) {
  2639.   if (back[i].status>=0) {
  2640.     char s[256]; 
  2641.     s[0]='\0';
  2642.     back_infostr(back,i,j,s);
  2643.     strcatbuff(s,LF);
  2644.     fprintf(fp,"%s",s);
  2645.   }
  2646. }
  2647.  
  2648. // infos backing
  2649. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2650. void back_infostr(lien_back* back,int i,int j,char* s) {
  2651.   if (back[i].status>=0) {
  2652.     int aff=0;
  2653.     if (j & 1) {
  2654.       if (back[i].status==100) {
  2655.         strcatbuff(s,"CONNECT ");
  2656.       } else if (back[i].status==99) {
  2657.         strcatbuff(s,"INFOS ");
  2658.         aff=1;
  2659.       } else if (back[i].status==98 || back[i].status==97) {
  2660.         strcatbuff(s,"INFOSC");             // infos chunk
  2661.         aff=1;
  2662.       }
  2663.       else if (back[i].status>0) {
  2664. #if HTS_ANALYSTE==2
  2665.         strcatbuff(s,"WAIT ");
  2666. #else
  2667.         strcatbuff(s,"RECEIVE "); 
  2668. #endif
  2669.         aff=1; 
  2670.       }
  2671.     } 
  2672.     if (j & 2) {
  2673.       if (back[i].status==0) {
  2674.         switch (back[i].r.statuscode) {
  2675.         case 200:
  2676.           strcatbuff(s,"READY ");
  2677.           aff=1;
  2678.           break;
  2679. #if HTS_ANALYSTE==2
  2680.         default:
  2681.           strcatbuff(s,"ERROR ");
  2682.           break;
  2683. #else
  2684.         case -1:
  2685.           strcatbuff(s,"ERROR ");
  2686.           aff=1;
  2687.           break;
  2688.         case -2:
  2689.           strcatbuff(s,"TIMEOUT ");
  2690.           aff=1;
  2691.           break;
  2692.         case -3:
  2693.           strcatbuff(s,"TOOSLOW ");
  2694.           aff=1;
  2695.           break;
  2696.         case 400:
  2697.           strcatbuff(s,"BADREQUEST ");
  2698.           aff=1;
  2699.           break;
  2700.         case 401: case 403:
  2701.           strcatbuff(s,"FORBIDDEN ");
  2702.           aff=1;
  2703.           break;
  2704.         case 404:
  2705.           strcatbuff(s,"NOT FOUND ");
  2706.           aff=1;
  2707.           break;
  2708.         case 500:
  2709.           strcatbuff(s,"SERVERROR ");
  2710.           aff=1;
  2711.           break;
  2712.         default:
  2713.           {
  2714.             char s2[256];
  2715.             sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
  2716.             strcatbuff(s,s2);
  2717.           }
  2718.           aff=1;
  2719. #endif
  2720.         }
  2721.       }
  2722.     }
  2723.     
  2724.     if (aff) {
  2725.       {
  2726.         char s2[1024];
  2727.         sprintf(s2,"\"%s",back[i].url_adr); strcatbuff(s,s2);
  2728.         
  2729.         if (back[i].url_fil[0]!='/') strcatbuff(s,"/");
  2730.         sprintf(s2,"%s\" ",back[i].url_fil); strcatbuff(s,s2);
  2731.         sprintf(s,LLintP" "LLintP" ",(LLint)back[i].r.size,(LLint)back[i].r.totalsize); strcatbuff(s,s2);
  2732.       }
  2733.     }
  2734.   }
  2735. }
  2736.  
  2737. // -- backing --
  2738.  
  2739. #undef test_flush
  2740.